From 34cd75f77d0ca94dbdba4e6cc9451fe4d33e78b3 Mon Sep 17 00:00:00 2001
From: lichao <lichao@aiotlink.com>
Date: 星期三, 19 五月 2021 19:14:13 +0800
Subject: [PATCH] add api BHQueryProcs.

---
 src/topic_node.h |  136 +++++++++++++++++++++++++++++++++------------
 1 files changed, 100 insertions(+), 36 deletions(-)

diff --git a/src/topic_node.h b/src/topic_node.h
index 5a3b86e..1bb3611 100644
--- a/src/topic_node.h
+++ b/src/topic_node.h
@@ -20,7 +20,10 @@
 
 #include "msg.h"
 #include "socket.h"
+#include <atomic>
 #include <memory>
+#include <mutex>
+#include <vector>
 
 using namespace bhome_shm;
 using namespace bhome_msg;
@@ -34,18 +37,22 @@
 	SharedMemory &shm() { return shm_; }
 
 public:
-	typedef std::function<void(std::string &proc_id, const void *data, const int len)> DataCB;
 	TopicNode(SharedMemory &shm);
 	~TopicNode();
 
 	// topic node
 	bool Register(ProcInfo &proc, MsgCommonReply &reply_body, const int timeout_ms);
+	bool Unregister(ProcInfo &proc, MsgCommonReply &reply_body, const int timeout_ms);
 	bool Heartbeat(ProcInfo &proc, MsgCommonReply &reply_body, const int timeout_ms);
 	bool Heartbeat(const int timeout_ms);
+	bool QueryTopicAddress(BHAddress &dest, MsgQueryTopic &query, MsgQueryTopicReply &reply_body, const int timeout_ms);
+	bool QueryProcs(BHAddress &dest, MsgQueryProc &query, MsgQueryProcReply &reply_body, const int timeout_ms);
 
 	// topic rpc server
-	typedef std::function<bool(const std::string &client_proc_id, const MsgRequestTopic &request, MsgRequestTopicReply &reply)> ServerCB;
-	bool ServerStart(ServerCB const &cb, const int nworker = 2);
+	typedef std::function<bool(const std::string &client_proc_id, const MsgRequestTopic &request, MsgRequestTopicReply &reply)> ServerSyncCB;
+	typedef std::function<void(void *src_info, std::string &client_proc_id, MsgRequestTopic &request)> ServerAsyncCB;
+	bool ServerStart(ServerSyncCB const &cb, const int nworker = 2);
+	bool ServerStart(ServerAsyncCB const &cb, const int nworker = 2);
 	bool ServerRegisterRPC(MsgTopicList &topics, MsgCommonReply &reply, const int timeout_ms);
 	bool ServerRecvRequest(void *&src_info, std::string &proc_id, MsgRequestTopic &request, const int timeout_ms);
 	bool ServerSendReply(void *src_info, const MsgRequestTopicReply &reply);
@@ -53,8 +60,8 @@
 	// topic client
 	typedef std::function<void(const BHMsgHead &head, const MsgRequestTopicReply &reply)> RequestResultCB;
 	bool ClientStartWorker(RequestResultCB const &cb, const int nworker = 2);
-	bool ClientAsyncRequest(const MsgRequestTopic &request, std::string &msg_id, const RequestResultCB &rrcb = RequestResultCB());
-	bool ClientSyncRequest(const MsgRequestTopic &request, std::string &proc_id, MsgRequestTopicReply &reply, const int timeout_ms);
+	bool ClientAsyncRequest(const BHAddress &remote_addr, const MsgRequestTopic &request, std::string &msg_id, const RequestResultCB &rrcb = RequestResultCB());
+	bool ClientSyncRequest(const BHAddress &remote_addr, const MsgRequestTopic &request, std::string &proc_id, MsgRequestTopicReply &reply, const int timeout_ms);
 
 	// publish
 	bool Publish(const MsgPublish &pub, const int timeout_ms);
@@ -65,67 +72,124 @@
 	bool Subscribe(MsgTopicList &topics, MsgCommonReply &reply_body, const int timeout_ms);
 	bool RecvSub(std::string &proc_id, MsgPublish &pub, const int timeout_ms);
 
-	void Start(ServerCB const &server_cb, SubDataCB const &sub_cb, RequestResultCB &client_cb, int nworker = 2);
+	void Start(ServerAsyncCB const &server_cb, SubDataCB const &sub_cb, RequestResultCB &client_cb, int nworker = 2);
 	void Stop();
 
 private:
-	bool ClientQueryRPCTopic(const Topic &topic, bhome::msg::BHAddress &addr, const int timeout_ms);
+	MQId ssn() { return SockNode().id(); }
+	bool ClientQueryRPCTopic(const Topic &topic, BHAddress &addr, const int timeout_ms);
+	typedef MsgQueryTopicReply::BHNodeAddress NodeAddress;
+	int QueryTopicServers(const Topic &topic, std::vector<NodeAddress> &addr, const int timeout_ms);
 	const std::string &proc_id() { return info_.proc_id(); }
 
-	typedef bhome_msg::BHAddress Address;
+	typedef BHAddress Address;
 	class TopicQueryCache
 	{
 		class Impl
 		{
-			typedef std::unordered_map<Topic, Address> Store;
-			Store store_;
+			struct TimedRec {
+				Address addr_;
+				int64_t timestamp_;
+			};
+			typedef std::unordered_map<Topic, TimedRec> Records;
+			Records records_;
 
 		public:
 			bool Find(const Topic &topic, Address &addr)
 			{
-				auto pos = store_.find(topic);
-				if (pos != store_.end()) {
-					addr = pos->second;
-					return true;
-				} else {
-					return false;
+				auto pos = records_.find(topic);
+				if (pos != records_.end()) {
+					if (NowSec() - pos->second.timestamp_ < NodeTimeoutSec() / 2) {
+						addr = pos->second.addr_;
+						return true;
+					} else {
+						LOG_TRACE() << "topic dest cache timeout.";
+					}
 				}
+				return false;
 			}
-			bool Update(const Topic &topic, const Address &addr)
+			bool Store(const Topic &topic, const Address &addr)
 			{
-				store_[topic] = addr;
+				records_[topic] = {addr, NowSec()};
 				return true;
 			}
 		};
 		Synced<Impl> impl_;
-		// Impl &impl()
-		// {
-		// 	thread_local Impl impl;
-		// 	return impl;
-		// }
 
 	public:
 		bool Find(const Topic &topic, Address &addr) { return impl_->Find(topic, addr); }
-		bool Update(const Topic &topic, const Address &addr) { return impl_->Update(topic, addr); }
+		bool Store(const Topic &topic, const Address &addr) { return impl_->Store(topic, addr); }
 	};
 
 	// some sockets may be the same one, using functions make it easy to change.
+	enum { eSockStart,
+		   eSockNode = eSockStart,
+		   eSockPub = eSockNode,
+		   eSockServer,
+		   eSockClient,
+		   eSockSub,
+		   eSockEnd,
+	};
+	std::vector<std::shared_ptr<ShmSocket>> sockets_;
 
-	auto &SockNode() { return sock_node_; }
-	auto &SockPub() { return SockNode(); }
-	auto &SockSub() { return sock_sub_; }
-	auto &SockClient() { return sock_client_; }
-	auto &SockServer() { return sock_server_; }
-	bool IsRegistered() const { return registered_.load(); }
+	ShmSocket &SockNode() { return *sockets_[eSockNode]; }
+	ShmSocket &SockPub() { return *sockets_[eSockPub]; }
+	ShmSocket &SockSub() { return *sockets_[eSockSub]; }
+	ShmSocket &SockClient() { return *sockets_[eSockClient]; }
+	ShmSocket &SockServer() { return *sockets_[eSockServer]; }
 
-	ShmSocket sock_node_;
-	ShmSocket sock_client_;
-	ShmSocket sock_server_;
-	ShmSocket sock_sub_;
-	std::atomic<bool> registered_;
-	std::atomic<bool> registered_ever_;
+	void SetProcIndex(int index)
+	{
+		proc_index_ = index;
+		for (int i = eSockStart; i < eSockEnd; ++i) {
+			sockets_[i]->SetNodeProc(index, i);
+		}
+	}
+
+	enum State {
+		eStateUninited,
+		eStateUnregistered,
+		eStateOnline,
+		eStateOffline // heartbeat fail.
+	};
+	void state(const State st) { state_.store(st); }
+	void state_cas(State expected, const State val) { state_.compare_exchange_strong(expected, val); }
+	State state() const { return state_.load(); }
+	bool IsOnline() { return state() == eStateOnline; }
+	bool Init();
+	bool Valid() const { return state() != eStateUninited; }
+	std::mutex mutex_;
+	MQId ssn_id_ = 0;
+	std::atomic<State> state_;
+	int proc_index_ = -1;
 
 	TopicQueryCache topic_query_cache_;
+
+	class RecvQ
+	{
+	public:
+		void Write(BHMsgHead &&head, std::string &&body) { q_.push_back({std::move(head), std::move(body)}); }
+		bool Read(BHMsgHead &head, std::string &body)
+		{
+			if (q_.empty()) {
+				return false;
+			} else {
+				head = std::move(q_.front().head);
+				body = std::move(q_.front().body);
+				q_.pop_front();
+				return true;
+			}
+		}
+
+	private:
+		struct MsgData {
+			BHMsgHead head;
+			std::string body;
+		};
+		std::deque<MsgData> q_;
+	};
+	Synced<RecvQ> server_buffer_;
+	Synced<RecvQ> sub_buffer_;
 };
 
 #endif // end of include guard: TOPIC_NODE_YVKWA6TF

--
Gitblit v1.8.0