ngx_int_t ngx_http_upstream_init_consistent_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { /* ip max 15, :port max 6, maxweight is highest number of uchar */ u_char *last, hash_data[28]; uint32_t step; ngx_uint_t i, j, k, n; ngx_uint_t real_nodes, points_per_node; ngx_http_upstream_server_t *server; ngx_http_upstream_rr_peer_t *rr_peer; ngx_http_upstream_rr_peers_t *prr_peers; ngx_http_upstream_consistent_hash_buckets *buckets; ngx_http_upstream_consistent_hash_continuum *continuum; ngx_http_upstream_consistent_hash_srv_conf_t *uchscf; uchscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_consistent_hash_module); if (uchscf == NULL) { return NGX_ERROR; } if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { return NGX_ERROR; } prr_peers = us->peer.data; us->peer.init = ngx_http_upstream_init_consistent_hash_peer; buckets = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_buckets)); if (!us->servers) { return NGX_ERROR; } server = us->servers->elts; n = real_nodes = 0; for (i = 0; i < us->servers->nelts; i++) { n += server[i].naddrs; real_nodes += server[i].weight * server[i].naddrs; } /* * The optimal points number is Q/S * See the section 6.2 from the paper 'Dynamo: Amazon's Highly Available * Key-value Store' */ points_per_node = (ngx_uint_t) MMC_CONSISTENT_BUCKETS / real_nodes; if (points_per_node == 0) { points_per_node = 1; } continuum = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_continuum)); continuum->nodes = ngx_palloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_node) * MMC_CONSISTENT_BUCKETS); for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { rr_peer = ngx_http_upstream_consistent_hash_find_rr_peer(prr_peers, server[i].addrs[j].sockaddr); if (rr_peer == NULL) { return NGX_ERROR; } for (k = 0; k < (points_per_node * server[i].weight); k++) { last = ngx_snprintf(hash_data, 28, "%V-%ui", &server[i].addrs[j].name, k); continuum->nodes[continuum->nnodes].point = ngx_http_upstream_consistent_hash_node_point(hash_data, (last - hash_data)); continuum->nodes[continuum->nnodes].rr_peer = rr_peer; continuum->nnodes++; } } } ngx_qsort(continuum->nodes, continuum->nnodes, sizeof(ngx_http_upstream_consistent_hash_node), (const void*) ngx_http_upstream_consistent_hash_compare_continuum_nodes); step = (uint32_t) (0xffffffff / MMC_CONSISTENT_BUCKETS); for (i = 0; i < MMC_CONSISTENT_BUCKETS; i++) { buckets->bucket[i] = ngx_http_upstream_consistent_hash_find(continuum, step * i); } #if (CONSISTENT_DEBUG) ngx_http_upstream_consistent_hash_print_continuum(cf, continuum); ngx_http_upstream_consistent_hash_print_buckets(cf, buckets); #endif buckets->continuum = continuum; uchscf->data = buckets; return NGX_OK; }
ngx_int_t ngx_http_upstream_init_consistent_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { /* ip max 15, :port max 6, maxweight is highest number of uchar */ u_char hash_data[HASH_DATA_LENGTH]; uint32_t step; ngx_uint_t i, j, k, n, points = 0; ngx_http_upstream_server_t *server; ngx_http_upstream_consistent_hash_buckets *buckets; ngx_http_upstream_consistent_hash_continuum *continuum; for (i=0;i<HASH_DATA_LENGTH;i++) hash_data[i] = 0; step = (uint32_t) (0xffffffff / MMC_CONSISTENT_BUCKETS); buckets = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_buckets)); us->peer.init = ngx_http_upstream_init_consistent_hash_peer; if (!us->servers) { return NGX_ERROR; } server = us->servers->elts; for (n = 0, i = 0; i < us->servers->nelts; i++) { n += server[i].naddrs; points += server[i].weight * server[i].naddrs * MMC_CONSISTENT_POINTS; } continuum = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_continuum)); continuum->nodes = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_node) * points); for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { for (k = 0; k < ((MMC_CONSISTENT_POINTS * server[i].weight) / server[i].naddrs); k++) { ngx_snprintf(hash_data, 28, "%V-%ui", &server[i].addrs[j].name, k); continuum->nodes[continuum->nnodes].sockaddr = server[i].addrs[j].sockaddr; continuum->nodes[continuum->nnodes].socklen = server[i].addrs[j].socklen; continuum->nodes[continuum->nnodes].name = server[i].addrs[j].name; continuum->nodes[continuum->nnodes].name.data[server[i].addrs[j].name.len] = 0; continuum->nodes[continuum->nnodes].point = ngx_crc32_long(hash_data, ngx_strlen(hash_data)); continuum->nnodes++; } } } qsort(continuum->nodes, continuum->nnodes, sizeof(ngx_http_upstream_consistent_hash_node), (const void*) ngx_http_upstream_consistent_hash_compare_continuum_nodes); for (i = 0; i < MMC_CONSISTENT_BUCKETS; i++) { buckets->buckets[i] = ngx_http_upstream_consistent_hash_find(continuum, step * i); } #if (CONSISTENT_DEBUG) ngx_http_upstream_consistent_hash_print_continuum(cf, continuum); ngx_http_upstream_consistent_hash_print_buckets(cf, buckets); #endif buckets->continuum = continuum; us->peer.data = buckets; return NGX_OK; }