/** * translate a address-string into a network_address structure * * - if the address contains a colon we assume IPv4, * - ":3306" -> (tcp) "0.0.0.0:3306" * - if it starts with a / it is a unix-domain socket * - "/tmp/socket" -> (unix) "/tmp/socket" * * @param addr the address-struct * @param address the address string * @return 0 on success, -1 otherwise */ gint network_address_set_address(network_address *addr, const gchar *address) { gchar *s; g_return_val_if_fail(addr, -1); /* split the address:port */ if (address[0] == '/') return network_address_set_address_un(addr, address); if (NULL != (s = strchr(address, ':'))) { gint ret; char *ip_address = g_strndup(address, s - address); /* may be NULL for strdup(..., 0) */ char *port_err = NULL; guint port = strtoul(s + 1, &port_err, 10); if (*(s + 1) == '\0') { g_critical("%s: IP-address has to be in the form [<ip>][:<port>], is '%s'. No port number", G_STRLOC, address); ret = -1; } else if (*port_err != '\0') { g_critical("%s: IP-address has to be in the form [<ip>][:<port>], is '%s'. Failed to parse the port at '%s'", G_STRLOC, address, port_err); ret = -1; } else { ret = network_address_set_address_ip(addr, ip_address, port); } if (ip_address) g_free(ip_address); return ret; } /* perhaps it is a plain IP address, lets add the default-port */ return network_address_set_address_ip(addr, address, 3306); }
static gint admin_reload_backends( network_mysqld_con* con, GPtrArray* backend_addr_str_array, gint fail_flag ) { chassis* srv; network_backends_t* backends; GPtrArray* cons; gchar* s; gchar* new_backend_addr; guint i; //gchar ip_address[MAX_IP_PORT_STRING_LEN + 1]; admin_network_addr_t* addr; GPtrArray* addr_array; gint ret = EC_ADMIN_RELOAD_SUCCESS; gboolean all_same_flag = 1; guint server_cnt = 0; guint client_cnt = 0; srv = con->srv; backends = srv->priv->backends; cons = srv->priv->cons; //for test if (fail_flag == 1000) { admin_print_all_backend_cons(con->srv); return EC_ADMIN_RELOAD_SUCCESS; } if (backend_addr_str_array->len != backends->backends->len) { g_critical("%s: Number of refresh backends num is not matched, new backends :%d, orignal backends : %d", G_STRLOC, backend_addr_str_array->len , backends->backends->len); return EC_ADMIN_RELOAD_FAIL; } if (fail_flag != 0 && fail_flag != 1) { g_critical("%s: Fail flag of refresh backends must be 0 or 1, but the flag is %d", G_STRLOC, fail_flag); return EC_ADMIN_RELOAD_FAIL; } addr_array = g_ptr_array_new(); /* 1. 测试DR连通性 */ for (i = 0; i < backend_addr_str_array->len; ++i) { new_backend_addr = g_ptr_array_index(backend_addr_str_array, i); addr = g_new0(admin_network_addr_t, 1); g_ptr_array_add(addr_array, addr); s = strchr(new_backend_addr, ':'); if (NULL != s) { gint len; char * port_err = NULL; network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); //check whether all backends are same //to do check backend:127.0.0.1:3306, addr:ip:3306? if (all_same_flag && g_strcasecmp(new_backend_addr, backend->addr->name->str) != 0 || backend->state == BACKEND_STATE_DOWN) { all_same_flag = 0; } len = s - new_backend_addr; if (len <= MAX_IP_PORT_STRING_LEN) { memcpy(addr->ip_address, new_backend_addr, len); addr->ip_address[len] = '\0'; addr->port = strtoul(s + 1, &port_err, 10); } if (len > MAX_IP_PORT_STRING_LEN || *(s + 1) == '\0') { g_critical("%s: Reload IP-address has to be in the form [<ip>][:<port>], is '%s'. No port number", G_STRLOC, new_backend_addr); ret = EC_ADMIN_RELOAD_FAIL; } else if (*port_err != '\0') { g_critical("%s: Reload IP-address has to be in the form [<ip>][:<port>], is '%s'. Failed to parse the port at '%s'", G_STRLOC, new_backend_addr, port_err); ret = EC_ADMIN_RELOAD_FAIL; } else { addr->addr = network_address_new(); if (network_address_set_address_ip(addr->addr, addr->ip_address, addr->port)) { g_critical("%s: Reload IP-address %s : %d error", G_STRLOC, addr->ip_address, addr->port); ret = EC_ADMIN_RELOAD_FAIL; } //ping the ip address and port; //ret = network_address_set_address_ip(addr, ip_address, port); //to do } } else ret = EC_ADMIN_RELOAD_FAIL; if (EC_ADMIN_RELOAD_FAIL == ret) { g_ptr_array_free_all(addr_array, admin_network_addr_free); return ret; } } //backends are same if (all_same_flag) { g_ptr_array_free_all(addr_array, admin_network_addr_free); return EC_ADMIN_RELOAD_SUCCESS; } /* 2. 置当前所有backends为down */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); backend->state = BACKEND_STATE_DOWN; } g_mutex_unlock(backends->backends_mutex); /* 3. 当前backend为新地址 */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); addr = g_ptr_array_index(addr_array, i); network_address_copy(backend->addr, addr->addr); // backend->addr->name->len = 0; /* network refresh name */ // // if (network_address_set_address_ip(backend->addr, addr->ip_address, addr->port)) // { // g_critical("%s: Reload IP-address %s : %d error" // G_STRLOC, addr->ip_address, addr->port); // ret = EC_ADMIN_RELOAD_FAIL; // // break; // } } g_mutex_unlock(backends->backends_mutex); /* 4. 关闭proxy当前所有连接 */ g_mutex_lock(srv->priv->cons_mutex); for (i = 0; i < cons->len; ++i) { con = g_ptr_array_index(cons, i); //区分了是否为backends的连接 if (con->server && con->server->backend_idx != -1) { //g_assert(con->server->fd != -1); if (con->server->fd != -1) { //closesocket(con->server->fd); con->server->fd_bak = con->server->fd; /* 后端连接暂不关闭,让其正常处理正在进行的事件 */ con->server->fd = -1; con->server->disconnect_flag = 1; server_cnt++; } //g_assert(con->client && con->client->fd != -1); if (con->client && con->client->fd != -1) { // int c_fd = con->client->fd; // con->client->fd = -1; // closesocket(c_fd); /* 需主动关闭前端fd,防止前端一直等待,但会导致con资源没有释放 */ client_cnt++; } /* 以上操作可能产生一种情况:客户端请求已在DB执行成功,但前端认为连接已断开 */ switch(con->state) { case CON_STATE_CLOSE_CLIENT: case CON_STATE_CLOSE_SERVER: case CON_STATE_SEND_ERROR: case CON_STATE_ERROR: break; case CON_STATE_INIT: case CON_STATE_CONNECT_SERVER: case CON_STATE_READ_HANDSHAKE: case CON_STATE_SEND_HANDSHAKE: case CON_STATE_READ_AUTH: case CON_STATE_SEND_AUTH: case CON_STATE_READ_AUTH_RESULT: case CON_STATE_SEND_AUTH_RESULT: case CON_STATE_READ_AUTH_OLD_PASSWORD: case CON_STATE_SEND_AUTH_OLD_PASSWORD: break; case CON_STATE_READ_QUERY: case CON_STATE_SEND_QUERY: break; case CON_STATE_READ_QUERY_RESULT: case CON_STATE_SEND_QUERY_RESULT: // //需要主动关闭连接 // if (fail_flag == 1) // { // if (con->client->fd != -1) // { // closesocket(con->client->fd); // con->client->fd = -1; // } // } break; case CON_STATE_READ_LOCAL_INFILE_DATA: case CON_STATE_SEND_LOCAL_INFILE_DATA: case CON_STATE_READ_LOCAL_INFILE_RESULT: case CON_STATE_SEND_LOCAL_INFILE_RESULT: break; } } } g_message("%s reload backends: connection count %d, close server count %d, close client count %d", G_STRLOC, srv->priv->cons->len, server_cnt, client_cnt); g_mutex_unlock(srv->priv->cons_mutex); if (ret != EC_ADMIN_RELOAD_SUCCESS) goto destroy_end; /* 5. 再把后端状态置为unknown,接收新连接 */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); backend->state = BACKEND_STATE_UNKNOWN; } g_mutex_unlock(backends->backends_mutex); /* 6. 刷新配置 */ ret = admin_configure_flush_to_file(srv); destroy_end: g_ptr_array_free_all(addr_array, admin_network_addr_free); return ret; }