[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