[nginx] Stream: split_clients module.
Vladimir Homutov
vl at nginx.com
Tue Jul 12 14:38:02 UTC 2016
details: http://hg.nginx.org/nginx/rev/787dcc15b802
branches:
changeset: 6632:787dcc15b802
user: Vladimir Homutov <vl at nginx.com>
date: Tue Jul 12 17:34:52 2016 +0300
description:
Stream: split_clients module.
diffstat:
auto/modules | 10 +
auto/options | 5 +
src/stream/ngx_stream_split_clients_module.c | 244 +++++++++++++++++++++++++++
3 files changed, 259 insertions(+), 0 deletions(-)
diffs (297 lines):
diff -r 80875b75d27e -r 787dcc15b802 auto/modules
--- a/auto/modules Thu Jun 30 16:12:50 2016 +0300
+++ b/auto/modules Tue Jul 12 17:34:52 2016 +0300
@@ -1054,6 +1054,16 @@ if [ $STREAM != NO ]; then
. auto/module
fi
+ if [ $STREAM_SPLIT_CLIENTS = YES ]; then
+ ngx_module_name=ngx_stream_split_clients_module
+ ngx_module_deps=
+ ngx_module_srcs=src/stream/ngx_stream_split_clients_module.c
+ ngx_module_libs=
+ ngx_module_link=$STREAM_SPLIT_CLIENTS
+
+ . auto/module
+ fi
+
if [ $STREAM_RETURN = YES ]; then
ngx_module_name=ngx_stream_return_module
ngx_module_deps=
diff -r 80875b75d27e -r 787dcc15b802 auto/options
--- a/auto/options Thu Jun 30 16:12:50 2016 +0300
+++ b/auto/options Tue Jul 12 17:34:52 2016 +0300
@@ -120,6 +120,7 @@ STREAM_ACCESS=YES
STREAM_GEO=YES
STREAM_GEOIP=NO
STREAM_MAP=YES
+STREAM_SPLIT_CLIENTS=YES
STREAM_RETURN=YES
STREAM_UPSTREAM_HASH=YES
STREAM_UPSTREAM_LEAST_CONN=YES
@@ -303,6 +304,8 @@ use the \"--with-mail_ssl_module\" optio
--without-stream_access_module) STREAM_ACCESS=NO ;;
--without-stream_geo_module) STREAM_GEO=NO ;;
--without-stream_map_module) STREAM_MAP=NO ;;
+ --without-stream_split_clients_module)
+ STREAM_SPLIT_CLIENTS=NO ;;
--without-stream_return_module) STREAM_RETURN=NO ;;
--without-stream_upstream_hash_module)
STREAM_UPSTREAM_HASH=NO ;;
@@ -506,6 +509,8 @@ cat << END
--without-stream_access_module disable ngx_stream_access_module
--without-stream_geo_module disable ngx_stream_geo_module
--without-stream_map_module disable ngx_stream_map_module
+ --without-stream_split_clients_module
+ disable ngx_stream_split_clients_module
--without-stream_return_module disable ngx_stream_return_module
--without-stream_upstream_hash_module
disable ngx_stream_upstream_hash_module
diff -r 80875b75d27e -r 787dcc15b802 src/stream/ngx_stream_split_clients_module.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stream/ngx_stream_split_clients_module.c Tue Jul 12 17:34:52 2016 +0300
@@ -0,0 +1,244 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_stream.h>
+
+
+typedef struct {
+ uint32_t percent;
+ ngx_stream_variable_value_t value;
+} ngx_stream_split_clients_part_t;
+
+
+typedef struct {
+ ngx_stream_complex_value_t value;
+ ngx_array_t parts;
+} ngx_stream_split_clients_ctx_t;
+
+
+static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy,
+ void *conf);
+
+static ngx_command_t ngx_stream_split_clients_commands[] = {
+
+ { ngx_string("split_clients"),
+ NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
+ ngx_conf_split_clients_block,
+ NGX_STREAM_MAIN_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_stream_module_t ngx_stream_split_clients_module_ctx = {
+ NULL, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL /* merge server configuration */
+};
+
+
+ngx_module_t ngx_stream_split_clients_module = {
+ NGX_MODULE_V1,
+ &ngx_stream_split_clients_module_ctx, /* module context */
+ ngx_stream_split_clients_commands, /* module directives */
+ NGX_STREAM_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_stream_split_clients_variable(ngx_stream_session_t *s,
+ ngx_stream_variable_value_t *v, uintptr_t data)
+{
+ ngx_stream_split_clients_ctx_t *ctx =
+ (ngx_stream_split_clients_ctx_t *) data;
+
+ uint32_t hash;
+ ngx_str_t val;
+ ngx_uint_t i;
+ ngx_stream_split_clients_part_t *part;
+
+ *v = ngx_stream_variable_null_value;
+
+ if (ngx_stream_complex_value(s, &ctx->value, &val) != NGX_OK) {
+ return NGX_OK;
+ }
+
+ hash = ngx_murmur_hash2(val.data, val.len);
+
+ part = ctx->parts.elts;
+
+ for (i = 0; i < ctx->parts.nelts; i++) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "stream split: %uD %uD", hash, part[i].percent);
+
+ if (hash < part[i].percent || part[i].percent == 0) {
+ *v = part[i].value;
+ return NGX_OK;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *rv;
+ uint32_t sum, last;
+ ngx_str_t *value, name;
+ ngx_uint_t i;
+ ngx_conf_t save;
+ ngx_stream_variable_t *var;
+ ngx_stream_split_clients_ctx_t *ctx;
+ ngx_stream_split_clients_part_t *part;
+ ngx_stream_compile_complex_value_t ccv;
+
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_split_clients_ctx_t));
+ if (ctx == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &ctx->value;
+
+ if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ name = value[2];
+
+ if (name.data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &name);
+ return NGX_CONF_ERROR;
+ }
+
+ name.len--;
+ name.data++;
+
+ var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
+ if (var == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ var->get_handler = ngx_stream_split_clients_variable;
+ var->data = (uintptr_t) ctx;
+
+ if (ngx_array_init(&ctx->parts, cf->pool, 2,
+ sizeof(ngx_stream_split_clients_part_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ save = *cf;
+ cf->ctx = ctx;
+ cf->handler = ngx_stream_split_clients;
+ cf->handler_conf = conf;
+
+ rv = ngx_conf_parse(cf, NULL);
+
+ *cf = save;
+
+ if (rv != NGX_CONF_OK) {
+ return rv;
+ }
+
+ sum = 0;
+ last = 0;
+ part = ctx->parts.elts;
+
+ for (i = 0; i < ctx->parts.nelts; i++) {
+ sum = part[i].percent ? sum + part[i].percent : 10000;
+ if (sum > 10000) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "percent total is greater than 100%%");
+ return NGX_CONF_ERROR;
+ }
+
+ if (part[i].percent) {
+ last += part[i].percent * (uint64_t) 0xffffffff / 10000;
+ part[i].percent = last;
+ }
+ }
+
+ return rv;
+}
+
+
+static char *
+ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+{
+ ngx_int_t n;
+ ngx_str_t *value;
+ ngx_stream_split_clients_ctx_t *ctx;
+ ngx_stream_split_clients_part_t *part;
+
+ ctx = cf->ctx;
+ value = cf->args->elts;
+
+ part = ngx_array_push(&ctx->parts);
+ if (part == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (value[0].len == 1 && value[0].data[0] == '*') {
+ part->percent = 0;
+
+ } else {
+ if (value[0].len == 0 || value[0].data[value[0].len - 1] != '%') {
+ goto invalid;
+ }
+
+ n = ngx_atofp(value[0].data, value[0].len - 1, 2);
+ if (n == NGX_ERROR || n == 0) {
+ goto invalid;
+ }
+
+ part->percent = (uint32_t) n;
+ }
+
+ part->value.len = value[1].len;
+ part->value.valid = 1;
+ part->value.no_cacheable = 0;
+ part->value.not_found = 0;
+ part->value.data = value[1].data;
+
+ return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid percent value \"%V\"", &value[0]);
+ return NGX_CONF_ERROR;
+}
More information about the nginx-devel
mailing list