예제 #1
0
bool redis_builder::cluster_meet(acl::redis& redis,
	const acl::redis_node& node)
{
	acl::string buf(node.get_addr());
	const std::vector<acl::string>& tokens = buf.split2(":");
	if (tokens.size() != 2)
	{
		printf("%s: invalid addr: %s\r\n",
			__FUNCTION__, node.get_addr());
		return false;
	}

	if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
	{
		printf("%s: cluster meet %s %s error: %s\r\n",
			__FUNCTION__, tokens[0].c_str(), tokens[1].c_str(),
			redis.result_error());
		return false;
	}

	while (true)
	{
		if (cluster_meeting(redis, node.get_addr()) == true)
			break;
		acl_doze(meet_wait_);
	}
	return true;
}
예제 #2
0
bool redis_builder::add_node(const char* addr,
	const char* new_node_addr, bool slave)
{
	acl::redis_client client(new_node_addr);
	acl::redis redis(&client);

	acl::string buf(addr);
	const std::vector<acl::string>& tokens = buf.split2(":");
	if (tokens.size() != 2)
	{
		printf("%s: invalid addr: %s\r\n", __FUNCTION__, addr);
		return false;
	}

	// CLUSTER MEET master node
	if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
	{
		printf("%s: cluster meet %s %s error: %s\r\n", __FUNCTION__,
			tokens[0].c_str(), tokens[1].c_str(),
			redis.result_error());
		return false;
	}

	// wait for the master recognizing the slave
	while (true)
	{
		if (cluster_meeting(redis, addr) == true)
			break;
		acl_doze(meet_wait_);
	}

	if (!slave)
		return true;

	acl::string node_id;
	if (redis_util::get_node_id(addr, node_id) == false)
	{
		printf("%s: can't get master(%s)'s node_id\r\n",
			__FUNCTION__, addr);
		return false;
	}

	if (redis.cluster_replicate(node_id.c_str()) == false)
	{
		printf("%s: cluster replicate id: %s, error: %s, "
			"master_addr: %s, slave_addr: %s\r\n",
			__FUNCTION__, node_id.c_str(), redis.result_error(),
			addr, new_node_addr);
		return false;
	}

	return true;
}
예제 #3
0
	void read_respond_body(HWND hWnd)
	{
		acl_assert(hdr_res_);

		/* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */

		if (hdr_res_->hdr.content_length == 0
			|| (hdr_res_->hdr.content_length == -1
			&& hdr_res_->reply_status > 300
			&& hdr_res_->reply_status < 400))
		{
			data_.i_ptr = NULL;
			data_.i_dlen = 0;
			// 如果没有数据体,也发送消息通知调用者数据结束
			report(hWnd, HTTP_MSG_DAT);
			return;
		}

		res_ = http_res_new(hdr_res_);

#define BUF_LEN		8192

		char* buf;
		int   ret;

		while (true)
		{
			buf = (char*) acl_mymalloc(BUF_LEN);
			ret = read_respond_body(buf, BUF_LEN - 1);
			if (ret <= 0)
			{
				acl_myfree(buf);
				break;
			}
			buf[ret] = 0;

			data_.i_ptr = buf;
			data_.i_dlen = (size_t) ret;
			report(hWnd, HTTP_MSG_DAT);

			if (respond_over_)
				break;
			if (nwait_ > 0)
				acl_doze(nwait_);
		}

		data_.i_ptr = NULL;
		data_.i_dlen = 0;
		report(hWnd, HTTP_MSG_DAT);
	}
예제 #4
0
bool redis_builder::add_slave(const acl::redis_node& master,
	const acl::redis_node& slave)
{
	acl::redis_client client(slave.get_addr());
	acl::redis redis(&client);
	const char* master_addr = master.get_addr();
	if (master_addr == NULL || *master_addr == 0)
	{
		printf("%s: master addr null\r\n", __FUNCTION__);
		return false;
	}
	acl::string buf(master_addr);
	const std::vector<acl::string>& tokens = buf.split2(":");
	if (tokens.size() != 2)
	{
		printf("%s: invalid master_addr: %s\r\n",
			__FUNCTION__, master_addr);
		return false;
	}

	// CLUSTER MEET master node
	if (!redis.cluster_meet(tokens[0].c_str(), atoi(tokens[1].c_str())))
	{
		printf("%s: cluster meet %s %s error: %s\r\n",
			__FUNCTION__, tokens[0].c_str(), tokens[1].c_str(),
			redis.result_error());
		return false;
	}

	// wait for the master recognizing the slave
	while (true)
	{
		if (cluster_meeting(redis, master_addr) == true)
			break;
		acl_doze(meet_wait_);
	}

	if (redis.cluster_replicate(master.get_id()) == false)
	{
		printf("%s: cluster replicate id: %s, error: %s, addr: %s\r\n",
			__FUNCTION__, master.get_id(), redis.result_error(),
			slave.get_addr());
		return false;
	}

	return true;
}
예제 #5
0
파일: main.cpp 프로젝트: iYefeng/acl
	void* run(void)
	{
		acl_doze(500);

		for (int i = 0; i < __nloop; i++)
		{
			if (mutex_.lock() == false)
			{
				printf("lock error\r\n");
				break;
			}

			__count++;
//			acl_doze(100);
			if (__show)
				printf("thread-%lu locked ok\r\n",
					acl::thread::self());
			assert(mutex_.unlock());
//			acl_doze(10);
		}

		return NULL;
	}
예제 #6
0
파일: events_poll.c 프로젝트: iYefeng/acl
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_POLL *ev = (EVENT_POLL *) eventp;
	ACL_EVENT_TIMER *timer;
	int   nready, i, revents;
	acl_int64 delay;
	ACL_EVENT_FDTABLE *fdp;

	delay = eventp->delay_sec * 1000000 + eventp->delay_usec;
	if (delay < DELAY_MIN)
		delay = DELAY_MIN;

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 poll 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = timer->when - eventp->present;
		if (n <= 0)
			delay = 0;
		else if (n < delay)
			delay = n;
	}

	/* 调用 event_prepare 检查有多少个描述字需要通过 poll 进行检测 */

	if (event_prepare(eventp) == 0) {
		/* 说明无须 poll 检测 */

		if (eventp->ready_cnt == 0)
			/* 为避免循环过快,休眠一下 */
			acl_doze(delay > DELAY_MIN ? (int) delay / 1000 : 1);

		goto TAG_DONE;
	}

	/* 如果已经有描述字准备好则 poll 检测超时时间置 0 */

	if (eventp->ready_cnt > 0)
		delay = 0;

	/* 调用 poll 系统调用检测可用描述字 */

	nready = poll(ev->fds, eventp->fdcnt, (int) (delay / 1000));

	if (eventp->nested++ > 0) {
		acl_msg_error("%s(%d): recursive call", myname, __LINE__);
		exit (1);
	}
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_error("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
			exit (1);
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查 poll 的检测结果集合 */

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = acl_fdmap_ctx(ev->fdmap, ev->fds[i].fd);
		if (fdp == NULL || fdp->stream == NULL)
			continue;

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		revents = ev->fds[i].revents;

		/* 检查描述字是否出现异常 */

		if ((revents & (POLLHUP | POLLERR)) != 0) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
			continue;
		}

		/* 检查描述字是否可读 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)
			&& (revents & POLLIN) )
		{
			/* 给该描述字对象附加可读属性 */
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}

			if (fdp->listener)
				fdp->event_type |= ACL_EVENT_ACCEPT;

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而
			 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数
			 */
			else
				fdp->stream->read_ready = 1;
		}

		/* 检查描述字是否可写 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)
			&& (revents & POLLOUT))
		{

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}
		}
	}

TAG_DONE:

	event_timer_trigger(eventp);

	/* 处理准备好的描述字事件 */
	if (eventp->ready_cnt > 0)
		event_fire(eventp);

	eventp->nested--;
}
예제 #7
0
bool redis_builder::build_cluster()
{
	if (masters_.empty())
	{
		printf("%s: no master available!\r\n", __FUNCTION__);
		return false;
	}

	size_t range = MAX_SLOTS / masters_.size();
	size_t begin = 0, end = MAX_SLOTS % masters_.size() + range -1;

	// build every master node, and connect all of its slaves.

	std::vector<acl::redis_node*>::iterator it;
	for (it = masters_.begin(); it != masters_.end(); ++it)
	{
		if (it != masters_.begin())
			printf("----------------------------------------\r\n");

		(*it)->add_slot_range(begin, end);
		if (build_master(**it) == false)
			return false;
		begin = end + 1;
		end = end + range;
	}

	it = masters_.begin();
	acl::redis_client client((*it)->get_addr());
	acl::redis master(&client);

	// let one master to connect all other master nodes

	printf("===================================================\r\n");
	printf("Meeting all masters and slaves ...\r\n");

	std::vector<acl::redis_node*> all_slaves;
	std::vector<acl::redis_node*>::const_iterator cit;

	for (++it; it != masters_.end(); ++it)
	{
		if (cluster_meet(master, **it) == false)
			return false;
		const std::vector<acl::redis_node*>* slaves = (*it)->get_slaves();
		for (cit = slaves->begin(); cit != slaves->end(); ++cit)
			all_slaves.push_back(*cit);
	}

	while (true)
	{
		int nwait = 0;
		for (cit = all_slaves.begin(); cit != all_slaves.end(); ++cit)
		{
			if ((*cit)->is_connected())
				continue;
			if (cluster_meeting(master, (*cit)->get_addr()) == false)
				nwait++;
			else
				(*cit)->set_connected(true);
		}
		if (nwait == 0)
			break;
		acl_doze(meet_wait_);
	}

	/////////////////////////////////////////////////////////////////////

	printf("===================================================\r\n");
	printf("All nodes of cluster:\r\n");

	const std::map<acl::string, acl::redis_node*>* nodes;
	if ((nodes = master.cluster_nodes())== NULL)
	{
		printf("%s: can't get cluster nodes, addr: %s\r\n",
			__FUNCTION__, client.get_stream()->get_peer(true));
		return false;
	}

	redis_status::show_nodes(nodes);
	return true;
}
예제 #8
0
const redis_result* redis_command::run(redis_client_cluster* cluster,
	size_t nchild, int* timeout /* = NULL */)
{
	redis_client* conn = peek_conn(cluster, slot_);

	// 如果没有找到可用的连接对象,则直接返回 NULL 表示出错
	if (conn == NULL)
	{
		logger_error("peek_conn NULL, slot_: %d", slot_);
		return NULL;
	}

	set_client_addr(*conn);
	conn->set_check_addr(check_addr_);

	redis_result_t type;
	bool  last_moved = false;
	int   n = 0;

	while (n++ < redirect_max_)
	{
		// 根据请求过程是否采用内存分片方式调用不同的请求过程
		if (slice_req_)
			result_ = conn->run(dbuf_, *request_obj_, nchild, timeout);
		else
			result_ = conn->run(dbuf_, *request_buf_, nchild, timeout);

		// 如果连接异常断开,则需要进行重试
		if (conn->eof())
		{
			// 删除哈希槽中的地址映射关系以便下次操作时重新获取
			cluster->clear_slot(slot_);

			// 将连接对象归还给连接池对象
			conn->get_pool()->put(conn, false);

			// 如果连接断开且请求数据为空时,则无须重试
			if (request_obj_->get_size() == 0 && request_buf_->empty())
			{
				logger_error("not retry when no request!");
				return NULL;
			}

			// 将连接池对象置为不可用状态
			conn->get_pool()->set_alive(false);

			// 从连接池集群中顺序取得一个连接对象
			conn = peek_conn(cluster, slot_);
			if (conn == NULL)
			{
				logger_error("peek_conn NULL");
				return result_;
			}

			last_moved = true;
			clear(true);
			set_client_addr(*conn);
			continue;
		}

		if (result_ == NULL)
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);
			logger_error("result NULL");

			return NULL;
		}

		// 取得服务器的响应结果的类型,并进行分别处理
		type = result_->get_type();

		if (type == REDIS_RESULT_UNKOWN)
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);
			logger_error("unknown result type: %d", type);

			return NULL;
		}

		if (type != REDIS_RESULT_ERROR)
		{
			// 如果发生重定向过程,则设置哈希槽对应 redis 服务地址
			if (slot_ < 0 || !last_moved)
			{
				// 将连接对象归还给连接池对象
				conn->get_pool()->put(conn, true);
				return result_;
			}

			// XXX: 因为此处还要引用一次 conn 对象,所以将 conn
			// 归还给连接池的过程须放在此段代码之后
			const char* addr = conn->get_pool()->get_addr();
			cluster->set_slot(slot_, addr);

			// 将连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);

			return result_;
		}

#define	EQ(x, y) !strncasecmp((x), (y), sizeof(y) -1)

		// 对于结果类型为错误类型,则需要进一步判断是否是重定向指令
		const char* ptr = result_->get_error();
		if (ptr == NULL || *ptr == 0)
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);
			logger_error("result error: null");

			return result_;
		}

		// 如果出错信息为重定向指令,则执行重定向过程
		if (EQ(ptr, "MOVED"))
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);

			const char* addr = get_addr(ptr);
			if (addr == NULL)
			{
				logger_warn("MOVED invalid, ptr: %s", ptr);
				return result_;
			}

			conn = redirect(cluster, addr);

			if (conn == NULL)
			{
				logger_error("redirect NULL, addr: %s", addr);
				return result_;
			}

			ptr = conn->get_pool()->get_addr();

			set_client_addr(ptr);

			if (n >= 2 && redirect_sleep_ > 0
				&& strcmp(ptr, addr) != 0)
			{
				logger("redirect %d, curr %s, waiting %s ...",
					n, ptr, addr);
				acl_doze(redirect_sleep_);
			}

			last_moved = true;

			// 需要保存哈希槽值
			clear(true);
		}
		else if (EQ(ptr, "ASK"))
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);

			const char* addr = get_addr(ptr);
			if (addr == NULL)
			{
				logger_warn("ASK invalid, ptr: %s", ptr);
				return result_;
			}

			conn = redirect(cluster, addr);
			if (conn == NULL)
			{
				logger_error("redirect NULL, addr: %s", addr);
				return result_;
			}

			ptr = conn->get_pool()->get_addr();

			set_client_addr(ptr);

			if (n >= 2 && redirect_sleep_ > 0
				&& strcmp(ptr, addr) != 0)
			{
				logger("redirect %d, curr %s, waiting %s ...",
					n, ptr, addr);
				acl_doze(redirect_sleep_);
			}

			result_ = conn->run(dbuf_, "ASKING\r\n", 0);
			if (result_ == NULL)
			{
				logger_error("ASKING's reply null");
				return NULL;
			}

			const char* status = result_->get_status();
			if (status == NULL || strcasecmp(status, "OK") != 0)
			{
				logger_error("ASKING's reply error: %s",
					status ? status : "null");
				return NULL;
			}

			last_moved = false;
			clear(true);
		}

		// 处理一个主结点失效的情形
		else if (EQ(ptr, "CLUSTERDOWN"))
		{
			cluster->clear_slot(slot_);

			if (redirect_sleep_ > 0)
			{
				logger("%s: redirect %d, slot %d, waiting %s ...",
					conn->get_pool()->get_addr(),
					n, slot_, ptr);
				acl_doze(redirect_sleep_);
			}

			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);

			conn = peek_conn(cluster, -1);
			if (conn == NULL)
			{
				logger_error("peek_conn NULL");
				return result_;
			}

			clear(true);
			set_client_addr(*conn);
		}

		// 对于其它错误类型,则直接返回本次得到的响应结果对象
		else
		{
			// 将旧连接对象归还给连接池对象
			conn->get_pool()->put(conn, true);

			logger_error("server error: %s", ptr);
			if (!slice_req_)
				logger_error("request: %s",
					request_buf_->c_str());
			return result_;
		}
	}

	if (conn != NULL)
		conn->get_pool()->put(conn, true);

	logger_warn("too many redirect: %d, max: %d", n, redirect_max_);
	return NULL;
}