[master] b90b60d0a shard director: add optional weight parameter to .add_backend()
Dridi Boukelmoune
dridi at varni.sh
Tue Jun 9 20:43:06 UTC 2020
On Tue, Jun 9, 2020 at 5:03 PM Nils Goroll <nils.goroll at uplex.de> wrote:
>
>
> commit b90b60d0a066f1aa7302a70125cb91cdfa605119
> Author: Nils Goroll <nils.goroll at uplex.de>
> Date: Tue Jun 9 19:02:00 2020 +0200
>
> shard director: add optional weight parameter to .add_backend()
>
> We implement weights by scaling the number of replicas of each backend.
> The replicas parameter of .reconfigure() remains a minimum.
>
> For existing vtcs, the Debug hashcircle output has been compared
> before/after this change to ensure that behaviour is exactly equivalent.
>
> For for wighted backends, it has been checked that the number of
> instances per host on the hashcircle matches the expectation.
>
> Also refactor and clean up some of the code:
>
> - consistently make the number of ring points a uint32_t
> - some constification
>
> Ref #3276
>
> diff --git a/bin/varnishtest/tests/d00041.vtc b/bin/varnishtest/tests/d00041.vtc
> new file mode 100644
> index 000000000..bd79cfff1
> --- /dev/null
> +++ b/bin/varnishtest/tests/d00041.vtc
> @@ -0,0 +1,224 @@
> +varnishtest "d00017.vtc but with weights"
> +
> +server s1 {
> + rxreq
> + txresp -body "ech3Ooj"
> +} -start
> +
> +server s2 {
> + rxreq
> + txresp -body "ieQu2qua"
> +} -start
> +
> +server s3 {
> + rxreq
> + txresp -body "xiuFi3Pe"
> +} -start
> +
> +varnish v1 -vcl+backend {
> + import std;
> + import directors;
> + import blob;
> +
> + sub vcl_init {
> + new vd = directors.shard();
> + vd.debug(3);
> + if (!vd.add_backend(s1)) {
> + std.log("add s1 failed");
> + }
> + if (!vd.add_backend(s2, weight=2)) {
> + std.log("add s2 failed");
> + }
> + if (!vd.add_backend(s3, weight=3)) {
> + std.log("add s3 failed");
> + }
> + if (!vd.reconfigure(replicas=25)) {
> + std.log("reconfigure failed");
Any reason not to return(fail("reason")) instead of std.log() calls?
> + }
> + }
> +
> + sub vcl_recv {
> + set req.backend_hint = vd.backend(by=BLOB,
> + key_blob=blob.decode(HEX, encoded=
> + regsub(req.url, "^/", "")));
> + return(pass);
> + }
> +
> +} -start
> +
> +logexpect l1 -v v1 -g raw -d 1 {
> + expect 0 0 CLI "^Rd vcl.load"
> +
> + expect 0 = Debug {^shard: hashcircle.* 0. = .point = *238d0ef, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 1. = .point = *321c598, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 2. = .point = *3b6b56a, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 3. = .point = *408ec1e, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 4. = .point = *66986a7, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 5. = .point = *7e41e30, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 6. = .point = *b749e7b, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 7. = .point = *e543430, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 8. = .point = *10136c05, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 9. = .point = *102d847f, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 10. = .point = *1112f910, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 11. = .point = *1119a7c7, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 12. = .point = *14d95c44, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 13. = .point = *150fea1f, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 14. = .point = *1643ecb6, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 15. = .point = *189ff2f2, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 16. = .point = *19cfe9f3, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 17. = .point = *1e1c78c3, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 18. = .point = *1fe0dea0, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 19. = .point = *22464ee9, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 20. = .point = *22b35675, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 21. = .point = *2363bebb, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 22. = .point = *24f827bb, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 23. = .point = *259eeccf, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 24. = .point = *26f0c3e7, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 25. = .point = *271874d4, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 26. = .point = *28340f35, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 27. = .point = *285e8475, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 28. = .point = *28ec7a6f, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 29. = .point = *299c6298, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 30. = .point = *2aedc3f7, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 31. = .point = *2b031742, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 32. = .point = *2da0e37b, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 33. = .point = *310bd2ca, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 34. = .point = *31e5f2df, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 35. = .point = *32d6b3ed, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 36. = .point = *33047373, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 37. = .point = *3392487a, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 38. = .point = *37597c4c, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 39. = .point = *3f6b2b89, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 40. = .point = *43cf6426, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 41. = .point = *46a58f28, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 42. = .point = *4b1f5b22, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 43. = .point = *523723f2, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 44. = .point = *539234db, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 45. = .point = *564ca84f, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 46. = .point = *58501380, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 47. = .point = *58704432, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 48. = .point = *5b1bcbbe, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 49. = .point = *5d2df428, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 50. = .point = *5fa294ee, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 51. = .point = *606fd878, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 52. = .point = *60dded53, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 53. = .point = *616cdb68, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 54. = .point = *6257bc27, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 55. = .point = *64014b25, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 56. = .point = *6918f467, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 57. = .point = *6a08c380, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 58. = .point = *6bfd5a2d, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 59. = .point = *6c0b607a, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 60. = .point = *6c74d296, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 61. = .point = *6e040182, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 62. = .point = *6e3819f7, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 63. = .point = *720ec1a4, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 64. = .point = *7232b381, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 65. = .point = *74c384ad, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 66. = .point = *76d47350, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 67. = .point = *791eb3a3, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 68. = .point = *7a048f20, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 69. = .point = *7f874929, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 70. = .point = *83ce71ce, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 71. = .point = *888b6447, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 72. = .point = *8997c018, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 73. = .point = *89b7d09c, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 74. = .point = *8aa6b5b4, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 75. = .point = *8ae34bde, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 76. = .point = *8b382e03, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 77. = .point = *8b47e6ac, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 78. = .point = *8bc76115, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 79. = .point = *8bc8bc11, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 80. = .point = *8e2d3849, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 81. = .point = *8e7e012c, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 82. = .point = *8f5b4c63, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 83. = .point = *94a94162, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 84. = .point = *99892987, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 85. = .point = *9a6f2f00, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 86. = .point = *9b970b49, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 87. = .point = *9e09a3a7, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 88. = .point = *9ef9125d, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 89. = .point = *9f33cd30, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 90. = .point = *9fc69b51, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 91. = .point = *a19f99eb, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 92. = .point = *a28b9595, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 93. = .point = *a3582038, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 94. = .point = *a4b6a3b9, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 95. = .point = *a66da9cb, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 96. = .point = *a8657c76, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 97. = .point = *a8afe9c4, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 98. = .point = *aa488703, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 99. = .point = *ac7b4454, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 100. = .point = *ad923ad3, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 101. = .point = *ae8946c6, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 102. = .point = *b197e339, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 103. = .point = *b3c305e6, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 104. = .point = *b4dab004, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 105. = .point = *b6bf43ea, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 106. = .point = *b9004d3d, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 107. = .point = *b96b6455, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 108. = .point = *b9a0edb9, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 109. = .point = *b9ec6465, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 110. = .point = *bb8eed4d, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 111. = .point = *bbcc0bad, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 112. = .point = *bcfea141, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 113. = .point = *be300622, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 114. = .point = *bf514d68, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 115. = .point = *c1afc7d2, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 116. = .point = *c2542a5d, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 117. = .point = *c6c43fa7, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 118. = .point = *c945958a, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 119. = .point = *c9f304a4, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 120. = .point = *cb896aa8, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 121. = .point = *cbd9198a, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 122. = .point = *ccd61dad, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 123. = .point = *d07e4431, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 124. = .point = *d21fe35f, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 125. = .point = *d4c93105, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 126. = .point = *d570b815, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 127. = .point = *d7de63b6, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 128. = .point = *d8634aef, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 129. = .point = *d92d916d, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 130. = .point = *d937a7df, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 131. = .point = *dac52229, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 132. = .point = *db7840f0, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 133. = .point = *dd5c6bef, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 134. = .point = *dded5798, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 135. = .point = *dfd5333b, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 136. = .point = *e183345a, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 137. = .point = *e2c71c27, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 138. = .point = *e49bf9d8, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 139. = .point = *e72bc224, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 140. = .point = *e8b27f41, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 141. = .point = *e991584c, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 142. = .point = *ea201c5e, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 143. = .point = *ec8891c5, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 144. = .point = *edcc8dd9, host = 1.}
> + expect 0 = Debug {^shard: hashcircle.* 145. = .point = *ef6b4ab5, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 146. = .point = *f08ad325, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 147. = .point = *f3325ba2, host = 2.}
> + expect 0 = Debug {^shard: hashcircle.* 148. = .point = *f6530dd1, host = 0.}
> + expect 0 = Debug {^shard: hashcircle.* 149. = .point = *fc28e8d2, host = 2.}
> +
> + expect 0 = CLI Loaded
> +
> + expect * = Debug {^shard: lookup key 564ca84f idx 45 host 0}
> + expect * = Debug {^shard: lookup key 19cfe9f3 idx 16 host 1}
> + expect * = Debug {^shard: lookup key 46a58f28 idx 41 host 2}
> +} -start
> +
> +client c1 {
> + txreq -url /564ca84f
> + rxresp
> + expect resp.body == "ech3Ooj"
> +
> + txreq -url /19cfe9f3
> + rxresp
> + expect resp.body == "ieQu2qua"
> +
> + txreq -url /46a58f28
> + rxresp
> + expect resp.body == "xiuFi3Pe"
> +} -run
> +
> +logexpect l1 -wait
> diff --git a/lib/libvmod_directors/shard_cfg.c b/lib/libvmod_directors/shard_cfg.c
> index 6276e1728..3f478ecf1 100644
> --- a/lib/libvmod_directors/shard_cfg.c
> +++ b/lib/libvmod_directors/shard_cfg.c
> @@ -55,6 +55,7 @@ struct shard_change_task {
> #define SHARD_CHANGE_TASK_MAGIC 0x1e1168af
> enum shard_change_task_e task;
> void *priv;
> + VCL_REAL weight;
> VSTAILQ_ENTRY(shard_change_task) list;
> };
>
> @@ -127,7 +128,7 @@ shard_change_finish(struct shard_change *change)
> VSTAILQ_INIT(&change->tasks);
> }
>
> -static void
> +static struct shard_change_task *
> shard_change_task_add(VRT_CTX, struct shard_change *change,
> enum shard_change_task_e task_e, void *priv)
> {
> @@ -139,15 +140,17 @@ shard_change_task_add(VRT_CTX, struct shard_change *change,
> if (task == NULL) {
> shard_err0(ctx, change->shardd,
> "could not get workspace for task");
> - return;
> + return (NULL);
> }
> INIT_OBJ(task, SHARD_CHANGE_TASK_MAGIC);
> task->task = task_e;
> task->priv = priv;
> VSTAILQ_INSERT_TAIL(&change->tasks, task, list);
> +
> + return (task);
> }
>
> -static inline VCL_BOOL
> +static inline struct shard_change_task *
> shard_change_task_backend(VRT_CTX,
> struct vmod_priv *priv, const struct sharddir *shardd,
> enum shard_change_task_e task_e, VCL_BACKEND be, VCL_STRING ident,
> @@ -161,22 +164,20 @@ shard_change_task_backend(VRT_CTX,
>
> change = shard_change_get(ctx, priv, shardd);
> if (change == NULL)
> - return (0);
> + return (NULL);
>
> b = WS_Alloc(ctx->ws, sizeof(*b));
> if (b == NULL) {
> shard_err(ctx, shardd, ".%s_backend() WS_Alloc() failed",
> task_e == ADD_BE ? "add" : "remove");
> - return (0);
> + return (NULL);
> }
>
> b->backend = be;
> b->ident = ident != NULL && *ident != '\0' ? ident : NULL;
> b->rampup = rampup;
>
> - shard_change_task_add(ctx, change, task_e, b);
> -
> - return (1);
> + return (shard_change_task_add(ctx, change, task_e, b));
> }
>
> /*
> @@ -186,11 +187,21 @@ shard_change_task_backend(VRT_CTX,
> VCL_BOOL
> shardcfg_add_backend(VRT_CTX, struct vmod_priv *priv,
> const struct sharddir *shardd, VCL_BACKEND be, VCL_STRING ident,
> - VCL_DURATION rampup)
> + VCL_DURATION rampup, VCL_REAL weight)
> {
> + struct shard_change_task *task;
> +
> + assert (weight >= 1);
> AN(be);
> - return (shard_change_task_backend(ctx, priv, shardd, ADD_BE,
> - be, ident, rampup));
> +
> + task = shard_change_task_backend(ctx, priv, shardd, ADD_BE,
> + be, ident, rampup);
> +
> + if (task == NULL)
> + return (0);
> +
> + task->weight = weight;
> + return (1);
> }
>
> VCL_BOOL
> @@ -198,7 +209,7 @@ shardcfg_remove_backend(VRT_CTX, struct vmod_priv *priv,
> const struct sharddir *shardd, VCL_BACKEND be, VCL_STRING ident)
> {
> return (shard_change_task_backend(ctx, priv, shardd, REMOVE_BE,
> - be, ident, 0));
> + be, ident, 0) != NULL);
> }
>
> VCL_BOOL
> @@ -212,9 +223,7 @@ shardcfg_clear(VRT_CTX, struct vmod_priv *priv, const struct sharddir *shardd)
> if (change == NULL)
> return (0);
>
> - shard_change_task_add(ctx, change, CLEAR, NULL);
> -
> - return (1);
> + return (shard_change_task_add(ctx, change, CLEAR, NULL) != NULL);
> }
>
> /*
> @@ -232,9 +241,11 @@ circlepoint_compare(const struct shard_circlepoint *a,
> }
>
> static void
> -shardcfg_hashcircle(struct sharddir *shardd, VCL_INT replicas)
> +shardcfg_hashcircle(struct sharddir *shardd)
> {
> - int i, j;
> + const struct shard_backend *backends, *b;
> + int j, h;
> + uint32_t i, n_points, r, rmax;
> const char *ident;
> const int len = 12; // log10(UINT32_MAX) + 2;
> char s[len];
> @@ -245,49 +256,60 @@ shardcfg_hashcircle(struct sharddir *shardd, VCL_INT replicas)
> AZ(shardd->hashcircle);
>
> assert(shardd->n_backend > 0);
> - AN(shardd->backend);
> -
> - shardd->hashcircle = calloc(shardd->n_backend * replicas,
> - sizeof(struct shard_circlepoint));
> - AN(shardd->hashcircle);
> + backends=shardd->backend;
> + AN(backends);
> +
> + n_points = 0;
> + rmax = (UINT32_MAX - 1) / shardd->n_backend;
> + for (b = backends; b < backends + shardd->n_backend; b++) {
> + CHECK_OBJ_NOTNULL(b->backend, DIRECTOR_MAGIC);
> + r = b->replicas;
> + if (r > rmax)
> + r = rmax;
> + n_points += r;
> + }
>
> - shardd->replicas = replicas;
> + assert(n_points < UINT32_MAX);
>
> - for (i = 0; i < shardd->n_backend; i++) {
> - CHECK_OBJ_NOTNULL(shardd->backend[i].backend, DIRECTOR_MAGIC);
> + shardd->n_points = n_points;
> + shardd->hashcircle = calloc(n_points, sizeof(struct shard_circlepoint));
> + AN(shardd->hashcircle);
>
> - ident = shardd->backend[i].ident
> - ? shardd->backend[i].ident
> - : VRT_BACKEND_string(shardd->backend[i].backend);
> + i = 0;
> + for (h = 0, b = backends; h < shardd->n_backend; h++, b++) {
> + ident = b->ident ? b->ident : VRT_BACKEND_string(b->backend);
>
> AN(ident);
> assert(ident[0] != '\0');
>
> - for (j = 0; j < replicas; j++) {
> + r = b->replicas;
> + if (r > rmax)
> + r = rmax;
> +
> + for (j = 0; j < r; j++) {
> assert(snprintf(s, len, "%d", j) < len);
> ss->n = 2;
> ssp[0] = ident;
> ssp[1] = s;
> ss->p = ssp;
> - shardd->hashcircle[i * replicas + j].point =
> - VRT_HashStrands32(ss);
> - shardd->hashcircle[i * replicas + j].host = i;
> + assert (i < n_points);
> + shardd->hashcircle[i].point = VRT_HashStrands32(ss);
> + shardd->hashcircle[i].host = h;
> + i++;
> }
> }
> - qsort( (void *) shardd->hashcircle, shardd->n_backend * replicas,
> + assert (i == n_points);
> + qsort( (void *) shardd->hashcircle, n_points,
> sizeof (struct shard_circlepoint), (compar) circlepoint_compare);
>
> if ((shardd->debug_flags & SHDBG_CIRCLE) == 0)
> return;
>
> - for (i = 0; i < shardd->n_backend; i++)
> - for (j = 0; j < replicas; j++)
> - SHDBG(SHDBG_CIRCLE, shardd,
> - "hashcircle[%5jd] = "
> - "{point = %8x, host = %2u}\n",
> - (intmax_t)(i * replicas + j),
> - shardd->hashcircle[i * replicas + j].point,
> - shardd->hashcircle[i * replicas + j].host);
> + for (i = 0; i < n_points; i++)
> + SHDBG(SHDBG_CIRCLE, shardd,
> + "hashcircle[%5jd] = {point = %8x, host = %2u}\n",
> + (intmax_t)i, shardd->hashcircle[i].point,
> + shardd->hashcircle[i].host);
> }
>
> /*
> @@ -394,7 +416,7 @@ shardcfg_backend_expand(const struct backend_reconfig *re)
>
> static void
> shardcfg_backend_add(struct backend_reconfig *re,
> - const struct shard_backend *b)
> + const struct shard_backend *b, uint32_t replicas)
> {
> unsigned i;
> struct shard_backend *bb = re->shardd->backend;
> @@ -419,6 +441,7 @@ shardcfg_backend_add(struct backend_reconfig *re,
>
> re->shardd->n_backend++;
> shardcfg_backend_copyin(&bb[i], b);
> + bb[i].replicas = replicas;
> }
>
> static void
> @@ -499,10 +522,11 @@ shardcfg_backend_finalize(struct backend_reconfig *re)
>
> static void
> shardcfg_apply_change(VRT_CTX, struct sharddir *shardd,
> - const struct shard_change *change)
> + const struct shard_change *change, VCL_INT replicas)
> {
> struct shard_change_task *task, *clear;
> const struct shard_backend *b;
> + uint32_t b_replicas;
>
> struct backend_reconfig re = {
> .shardd = shardd,
> @@ -550,7 +574,14 @@ shardcfg_apply_change(VRT_CTX, struct sharddir *shardd,
> b = shardcfg_backend_lookup(&re, task->priv);
>
> if (b == NULL) {
> - shardcfg_backend_add(&re, task->priv);
> + assert (task->weight >= 1);
> + if (replicas * task->weight > UINT32_MAX)
> + b_replicas = UINT32_MAX;
> + else
> + b_replicas = replicas * task->weight;
> +
> + shardcfg_backend_add(&re, task->priv,
> + b_replicas);
> break;
> }
>
> @@ -599,7 +630,7 @@ shardcfg_reconfigure(VRT_CTX, struct vmod_priv *priv,
>
> sharddir_wrlock(shardd);
>
> - shardcfg_apply_change(ctx, shardd, change);
> + shardcfg_apply_change(ctx, shardd, change, replicas);
> shard_change_finish(change);
>
> if (shardd->hashcircle)
> @@ -612,7 +643,7 @@ shardcfg_reconfigure(VRT_CTX, struct vmod_priv *priv,
> return (0);
> }
>
> - shardcfg_hashcircle(shardd, replicas);
> + shardcfg_hashcircle(shardd);
> sharddir_unlock(shardd);
> return (1);
> }
> diff --git a/lib/libvmod_directors/shard_cfg.h b/lib/libvmod_directors/shard_cfg.h
> index 5c6f1e6b6..0b8b8612c 100644
> --- a/lib/libvmod_directors/shard_cfg.h
> +++ b/lib/libvmod_directors/shard_cfg.h
> @@ -30,7 +30,7 @@
>
> VCL_BOOL shardcfg_add_backend(VRT_CTX, struct vmod_priv *priv,
> const struct sharddir *shardd, VCL_BACKEND be, VCL_STRING ident,
> - VCL_DURATION rampup);
> + VCL_DURATION rampup, VCL_REAL weight);
> VCL_BOOL shardcfg_remove_backend(VRT_CTX, struct vmod_priv *priv,
> const struct sharddir *shardd, VCL_BACKEND be, VCL_STRING ident);
> VCL_BOOL shardcfg_clear(VRT_CTX, struct vmod_priv *priv,
> diff --git a/lib/libvmod_directors/shard_dir.c b/lib/libvmod_directors/shard_dir.c
> index 850aeebcf..001286011 100644
> --- a/lib/libvmod_directors/shard_dir.c
> +++ b/lib/libvmod_directors/shard_dir.c
> @@ -60,7 +60,7 @@ struct shard_be_info {
> struct shard_state {
> const struct vrt_ctx *ctx;
> struct sharddir *shardd;
> - int idx;
> + uint32_t idx;
>
> struct vbitmap *picklist;
> int pickcount;
> @@ -94,8 +94,10 @@ shard_lookup(const struct sharddir *shardd, const uint32_t key)
> {
> CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
>
> - const int n = shardd->n_backend * shardd->replicas;
> - int idx = -1, high = n, low = 0, i;
> + const uint32_t n = shardd->n_points;
> + uint32_t i, idx = UINT32_MAX, high = n, low = 0;
> +
> + assert (n < idx);
>
> do {
> i = (high + low) / 2 ;
> @@ -113,7 +115,7 @@ shard_lookup(const struct sharddir *shardd, const uint32_t key)
> high = i;
> else
> low = i;
> - } while (idx == -1);
> + } while (idx == UINT32_MAX);
>
> return (idx);
> }
> @@ -122,7 +124,6 @@ static int
> shard_next(struct shard_state *state, VCL_INT skip, VCL_BOOL healthy)
> {
> int c, chosen = -1;
> - uint32_t ringsz;
> VCL_BACKEND be;
> vtim_real changed;
> struct shard_be_info *sbe;
> @@ -134,8 +135,6 @@ shard_next(struct shard_state *state, VCL_INT skip, VCL_BOOL healthy)
> if (state->pickcount >= state->shardd->n_backend)
> return (-1);
>
> - ringsz = state->shardd->n_backend * state->shardd->replicas;
> -
> while (state->pickcount < state->shardd->n_backend && skip >= 0) {
>
> c = state->shardd->hashcircle[state->idx].host;
> @@ -174,7 +173,7 @@ shard_next(struct shard_state *state, VCL_INT skip, VCL_BOOL healthy)
> break;
> }
>
> - if (++(state->idx) == ringsz)
> + if (++(state->idx) == state->shardd->n_points)
> state->idx = 0;
> }
> return (chosen);
> diff --git a/lib/libvmod_directors/shard_dir.h b/lib/libvmod_directors/shard_dir.h
> index 03df1c312..3ad305180 100644
> --- a/lib/libvmod_directors/shard_dir.h
> +++ b/lib/libvmod_directors/shard_dir.h
> @@ -43,6 +43,7 @@ struct shard_backend {
> void *freeptr;
> };
> VCL_DURATION rampup;
> + uint32_t replicas;
> };
>
> struct vmod_directors_shard_param;
> @@ -68,7 +69,8 @@ struct sharddir {
>
> VCL_DURATION rampup_duration;
> VCL_REAL warmup;
> - VCL_INT replicas;
> +
> + uint32_t n_points;
> };
>
> static inline VCL_BACKEND
> diff --git a/lib/libvmod_directors/vmod.vcc b/lib/libvmod_directors/vmod.vcc
> index 054b6c34e..8ab9f12fa 100644
> --- a/lib/libvmod_directors/vmod.vcc
> +++ b/lib/libvmod_directors/vmod.vcc
> @@ -373,7 +373,7 @@ The association can be changed per backend request using the *param*
> argument of `xshard.backend()`_.
>
> $Method BOOL .add_backend(PRIV_TASK, BACKEND backend,
> - [STRING ident], [DURATION rampup])
> + [STRING ident], [DURATION rampup], [REAL weight])
>
> Add a backend *backend* to the director.
>
> @@ -388,6 +388,12 @@ defaults to the backend name.
> backend. Otherwise, the per-director rampup time is used (see
> `xshard.set_rampup()`_).
>
> +*weight*: Optionally specify a weight to scale the
> +`xshard.reconfigure()`_ *replicas* parameter. *weight* is limited to
> +at least 1. Values above 10 probably do not make much sense. The
> +effect of *weight* is also capped such that the total number of
> +replicas does not exceed `UINT32_MAX`.
> +
> NOTE: Backend changes need to be finalized with
> `xshard.reconfigure()`_ and are only supported on one
> shard director at a time.
> diff --git a/lib/libvmod_directors/vmod_shard.c b/lib/libvmod_directors/vmod_shard.c
> index c3ec5d837..8a8bda9a2 100644
> --- a/lib/libvmod_directors/vmod_shard.c
> +++ b/lib/libvmod_directors/vmod_shard.c
> @@ -305,6 +305,8 @@ VCL_BOOL v_matchproto_(td_directors_shard_add_backend)
> vmod_shard_add_backend(VRT_CTX, struct vmod_directors_shard *vshard,
> struct VARGS(shard_add_backend) *args)
> {
> + VCL_REAL weight = 1;
> +
> CHECK_OBJ_NOTNULL(vshard, VMOD_SHARD_SHARD_MAGIC);
>
> if (args->backend == NULL) {
> @@ -313,10 +315,14 @@ vmod_shard_add_backend(VRT_CTX, struct vmod_directors_shard *vshard,
> return (0);
> }
>
> + if (args->valid_weight && args->weight > 1)
> + weight = args->weight;
> +
Shouldn't we VRT_fail() if the supplied weight is not valid?
> return shardcfg_add_backend(ctx, args->arg1,
> vshard->shardd, args->backend,
> args->valid_ident ? args->ident : NULL,
> - args->valid_rampup ? args->rampup : nan(""));
> + args->valid_rampup ? args->rampup : nan(""),
> + weight);
> }
>
> VCL_BOOL v_matchproto_(td_directors_shard_remove_backend)
> _______________________________________________
> varnish-commit mailing list
> varnish-commit at varnish-cache.org
> https://www.varnish-cache.org/lists/mailman/listinfo/varnish-commit
More information about the varnish-commit
mailing list