aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2015-03-02 18:41:29 +0300
committerRoman Arutyunyan <arut@nginx.com>2015-03-02 18:41:29 +0300
commitbf7d76b943d04b3f05a500689a111f54f27fe80f (patch)
tree22fad14d57d8b5d164d4b2b4ba2563b9fd865183
parentde3adad8073d20404ce2e2b54f73aa9c72ce4e88 (diff)
downloadnginx-bf7d76b943d04b3f05a500689a111f54f27fe80f.tar.gz
nginx-bf7d76b943d04b3f05a500689a111f54f27fe80f.zip
Upstream hash: speedup consistent hash init.
Repeatedly calling ngx_http_upstream_add_chash_point() to create the points array in sorted order, is O(n^2) to the total weight. This can cause nginx startup and reconfigure to be substantially delayed. For example, when total weight is 1000, startup takes 5s on a modern laptop. Replace this with a linear insertion followed by QuickSort and duplicates removal. Startup for total weight of 1000 reduces to 40ms. Based on a patch by Wai Keen Woon.
-rw-r--r--src/http/modules/ngx_http_upstream_hash_module.c52
1 files changed, 31 insertions, 21 deletions
diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c
index 777e180a5..a1f0ff3c9 100644
--- a/src/http/modules/ngx_http_upstream_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_hash_module.c
@@ -49,8 +49,8 @@ static ngx_int_t ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc,
static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us);
-static void ngx_http_upstream_add_chash_point(
- ngx_http_upstream_chash_points_t *points, uint32_t hash, ngx_str_t *server);
+static int ngx_libc_cdecl
+ ngx_http_upstream_chash_cmp_points(const void *one, const void *two);
static ngx_uint_t ngx_http_upstream_find_chash_point(
ngx_http_upstream_chash_points_t *points, uint32_t hash);
static ngx_int_t ngx_http_upstream_init_chash_peer(ngx_http_request_t *r,
@@ -360,12 +360,27 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
ngx_crc32_update(&hash, (u_char *) &prev_hash, sizeof(uint32_t));
ngx_crc32_final(hash);
- ngx_http_upstream_add_chash_point(points, hash, &peer->server);
+ points->point[points->number].hash = hash;
+ points->point[points->number].server = server;
+ points->number++;
prev_hash = hash;
}
}
+ ngx_qsort(points->point,
+ points->number,
+ sizeof(ngx_http_upstream_chash_point_t),
+ ngx_http_upstream_chash_cmp_points);
+
+ for (i = 0, j = 1; j < points->number; j++) {
+ if (points->point[i].hash != points->point[j].hash) {
+ points->point[++i] = points->point[j];
+ }
+ }
+
+ points->number = i + 1;
+
hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module);
hcf->points = points;
@@ -373,28 +388,23 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
}
-static void
-ngx_http_upstream_add_chash_point(ngx_http_upstream_chash_points_t *points,
- uint32_t hash, ngx_str_t *server)
+static int ngx_libc_cdecl
+ngx_http_upstream_chash_cmp_points(const void *one, const void *two)
{
- size_t size;
- ngx_uint_t i;
- ngx_http_upstream_chash_point_t *point;
+ ngx_http_upstream_chash_point_t *first =
+ (ngx_http_upstream_chash_point_t *) one;
+ ngx_http_upstream_chash_point_t *second =
+ (ngx_http_upstream_chash_point_t *) two;
- i = ngx_http_upstream_find_chash_point(points, hash);
- point = &points->point[i];
+ if (first->hash < second->hash) {
+ return -1;
- if (point->hash == hash) {
- return;
- }
-
- size = (points->number - i) * sizeof(ngx_http_upstream_chash_point_t);
-
- ngx_memmove(point + 1, point, size);
+ } else if (first->hash > second->hash) {
+ return 1;
- points->number++;
- point->hash = hash;
- point->server = server;
+ } else {
+ return 0;
+ }
}