]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#8204 Improved RFC2782 shuffle when several, but not all, records have weight 0.
authorSergio Gelato <Sergio.Gelato@astro.su.se>
Sun, 6 Dec 2015 12:33:17 +0000 (13:33 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Mon, 22 Jun 2020 17:27:30 +0000 (17:27 +0000)
The fallback to a straight Fisher-Yates shuffle needs to occur whenever the
sum of the *remaining* weights is zero, or else the remaining records will
not be reordered. Testing only once at the beginning covers the case when
all weights are zero, and obviously no shuffling is needed when only one
weight is zero; but other weight combinations are possible, such as (1, 0, 0).

libraries/libldap/dnssrv.c

index 1503c068b6b88d03303568ab718ec8fee9ba803b..69c9bb5ff020e441618586b3995c7c45a26212d6 100644 (file)
@@ -216,36 +216,27 @@ static void srv_shuffle(srv_record *a, int n) {
        for (i=0; i<n; i++)
                total += a[i].weight;
 
-       /* all weights are zero, do a straight Fisher-Yates shuffle */
-       if (!total) {
-               while (n) {
-                       srv_record t;
-                       i = srv_rand() * n--;
-                       t = a[n];
-                       a[n] = a[i];
-                       a[i] = t;
-               }
-               return;
-       }
-
        /* Do a shuffle per RFC2782 Page 4 */
-       p = n;
-       for (i=0; i<n-1; i++) {
-               r = srv_rand() * total;
-               for (j=0; j<p; j++) {
-                       r -= a[j].weight;
-                       if (r < 0) {
-                               if (j) {
-                                       srv_record t = a[0];
-                                       a[0] = a[j];
-                                       a[j] = t;
+       for (p=n; p>1; a++, p--) {
+               if (!total) {
+                       /* all remaining weights are zero,
+                          do a straight Fisher-Yates shuffle */
+                       j = srv_rand() * p;
+               } else {
+                       r = srv_rand() * total;
+                       for (j=0; j<p; j++) {
+                               r -= a[j].weight;
+                               if (r < 0) {
+                                       total -= a[j].weight;
+                                       break;
                                }
-                               total -= a[0].weight;
-                               a++;
-                               p--;
-                               break;
                        }
                }
+               if (j && j<p) {
+                       srv_record t = a[0];
+                       a[0] = a[j];
+                       a[j] = t;
+               }
        }
 }
 #endif /* HAVE_RES_QUERY */