proxy_behavior cproxy_parse_behavior(char *behavior_str, proxy_behavior behavior_default) { // These are the default proxy behaviors. // struct proxy_behavior behavior = behavior_default; if (behavior_str == NULL || strlen(behavior_str) <= 0) { return behavior; } // Parse the key-value behavior_str, to override the defaults. // char *buff = trimstrdup(behavior_str); char *next = buff; while (next != NULL) { char *key_val = trimstr(strsep(&next, ",")); if (key_val != NULL) { cproxy_parse_behavior_key_val_str(key_val, &behavior); } } free(buff); return behavior; }
enum conflate_mgmt_cb_result on_conflate_ping_test(void *userdata, conflate_handle_t *handle, const char *cmd, bool direct, kvpair_t *form, conflate_form_result *r) { (void)userdata; (void)handle; (void)cmd; (void)direct; assert(userdata); // The form key-multivalues looks roughly like... // // servers // svrname1 // svrname2 // svr-svrname1 // host=mc1.foo.net // port=11211 // bucket=buck1 // usr=test1 // pwd=password // svr-svrname2 // host=mc2.foo.net // port=11211 // bucket=buck1 // usr=test1 // pwd=password // tests // test1 // test2 // def-test1 // ksize=16 // vsize=16 // iterations=500 // def-test2 // ksize=64 // vsize=524288 // iterations=50 // if (!form) { return RV_BADARG; } char detail_key[200]; // Discover test configuration. char **tests = get_key_values(form, "tests"); int nrecipes = charlistlen(tests); struct ping_test_recipe recipes[nrecipes+1]; memset(recipes, 0x00, sizeof(struct ping_test_recipe) * (nrecipes+1)); for (int j = 0; j < nrecipes; j++) { snprintf(detail_key, sizeof(detail_key), "def-%s", tests[j]); recipes[j].name = strdup(detail_key); assert(recipes[j].name); load_ping_recipe(get_key_values(form, detail_key), &recipes[j]); } // Initialize each server and run the tests char **servers = get_key_values(form, "servers"); for (int j = 0; servers != NULL && servers[j]; j++) { snprintf(detail_key, sizeof(detail_key), "svr-%s", servers[j]); if (settings.verbose > 1) { moxi_log_write("ping_test %s\n", detail_key); } proxy_behavior behavior; memset(&behavior, 0, sizeof(behavior)); char **props = get_key_values(form, detail_key); for (int k = 0; props && props[k]; k++) { cproxy_parse_behavior_key_val_str(props[k], &behavior); } ping_server(servers[j], recipes, &behavior, r); } /* The recipe memory allocations */ for (int j = 0; j < nrecipes; j++) { free(recipes[j].name); } return RV_OK; }
static void cproxy_on_new_config(void *data0, void *data1) { work_collect *completion = data0; proxy_main *m = completion->data; assert(m); kvpair_t *kvs = data1; assert(kvs); assert(is_listen_thread()); m->stat_configs++; uint32_t max_config_ver = 0; for (proxy *p = m->proxy_head; p != NULL; p = p->next) { pthread_mutex_lock(&p->proxy_lock); if (max_config_ver < p->config_ver) { max_config_ver = p->config_ver; } pthread_mutex_unlock(&p->proxy_lock); } uint32_t new_config_ver = max_config_ver + 1; if (settings.verbose > 2) { fprintf(stderr, "conc new_config_ver %u\n", new_config_ver); } // The kvs key-multivalues look roughly like... // // pool-customer1-a // svrname3 // pool-customer1-b // svrname1 // svrname2 // svr-svrname1 // host=mc1.foo.net // port=11211 // weight=1 // bucket=buck1 // usr=test1 // pwd=password // svr-svrnameX // host=mc2.foo.net // port=11211 // behavior-customer1-a // wait_queue_timeout=1000 // downstream_max=10 // behavior-customer1-b // wait_queue_timeout=1000 // downstream_max=10 // pool_drain-customer1-b // svrname1 // svrname3 // pools // customer1-a // customer1-b // bindings // 11221 // 11331 // char **pools = get_key_values(kvs, "pools"); char **bindings = get_key_values(kvs, "bindings"); if (pools == NULL) { goto fail; } int npools = 0; int nbindings = 0; while (pools && pools[npools]) npools++; while (bindings && bindings[nbindings]) nbindings++; if (nbindings > 0 && nbindings != npools) { if (settings.verbose > 1) { fprintf(stderr, "npools does not match nbindings\n"); } goto fail; } char **behavior_kvs = get_key_values(kvs, "behavior"); if (behavior_kvs != NULL) { // Update the default behavior. // proxy_behavior m_behavior = m->behavior; for (int k = 0; behavior_kvs[k]; k++) { char *bstr = trimstrdup(behavior_kvs[k]); if (bstr != NULL) { cproxy_parse_behavior_key_val_str(bstr, &m_behavior); free(bstr); } } m->behavior = m_behavior; } for (int i = 0; i < npools; i++) { char *pool_name = skipspace(pools[i]); if (pool_name != NULL && pool_name[0] != '\0') { char buf[200]; snprintf(buf, sizeof(buf), "pool-%s", pool_name); char **servers = get_key_values(kvs, trimstr(buf)); if (servers != NULL) { // Parse proxy-level behavior. // proxy_behavior proxyb = m->behavior; if (parse_kvs_behavior(kvs, "behavior", pool_name, &proxyb)) { if (settings.verbose > 1) { cproxy_dump_behavior(&proxyb, "conc proxy_behavior", 1); } } // The legacy way to get a port is through the bindings, // but they're also available as an inheritable // proxy_behavior field of port_listen. // int pool_port = proxyb.port_listen; if (i < nbindings && bindings != NULL && bindings[i]) { pool_port = atoi(skipspace(bindings[i])); } if (pool_port > 0) { // Number of servers in this pool. // int s = 0; while (servers[s]) s++; if (s > 0) { // Parse server-level behaviors, so we'll have an // array of behaviors, one entry for each server. // proxy_behavior_pool behavior_pool = { .base = proxyb, .num = s, .arr = calloc(s, sizeof(proxy_behavior)) }; if (behavior_pool.arr != NULL) { char *config_str = parse_kvs_servers("svr", pool_name, kvs, servers, &behavior_pool); if (config_str != NULL && config_str[0] != '\0') { if (settings.verbose > 2) { fprintf(stderr, "conc config: %s\n", config_str); } cproxy_on_new_pool(m, pool_name, pool_port, config_str, new_config_ver, &behavior_pool); free(config_str); } free(behavior_pool.arr); } else { if (settings.verbose > 1) { fprintf(stderr, "ERROR: oom on re-config malloc\n");; } goto fail; } } else { // Note: ignore when no servers for an existing pool. // Because the config_ver won't be updated, we'll // fall into the empty_pool code path below. } } else {