PostOffice 类

/**
* \brief 系统的中心。
*/
class Postoffice {
public:
/**
* \brief 返回单例对象。
*/
static Postoffice* Get() {
static Postoffice e; return &e;
} /** \brief 返回持有的 Van 实例。 */
Van* van() { return van_; } /**
* \brief 启动系统。
*
* 本函数将会阻塞,直到所有节点都启动。
* \param argv0 用于日志的程序名。
* \param do_barrier 是否在所有节点都启动完成前阻塞当前线程。
*/
void Start(int customer_id, const char* argv0, const bool do_barrier); /**
* \brief 停止系统。
*
* 所有节点在退出前都应该调用该方法。
* \param do_barrier 是否在所有节点都停止前阻塞当前线程,默认为 true。
*/
void Finalize(const int customer_id, const bool do_barrier = true); /**
* \brief 向本系统添加一个 Customer。线程安全。
*/
void AddCustomer(Customer* customer); /**
* \brief 根据编号移除一个 Customer。线程安全。
*/
void RemoveCustomer(Customer* customer); /**
* \brief 获取给定编号的 Customer。线程安全。
* \param app_id 应用编号。
* \param customer_id Customer 编号。
* \param timeout 以秒位单位的超时。
* \return 如果不存在或者超时,返回 nullptr。
*/
Customer* GetCustomer(int app_id, int customer_id, int timeout = 0) const; /**
* \brief 获取给定编号的节点或节点组。线程安全。
*
* 如果是一个节点组的编号,那么返回所属的全部节点。否则,返回的列表只有一个节点元素。
*/
const std::vector<int>& GetNodeIDs(int node_id) const {
const auto it = node_ids_.find(node_id);
CHECK(it != node_ids_.cend()) << "node " << node_id << " doesn't exist";
return it->second;
} /**
* \brief 返回每个 Server 节点对应的键域。
*/
const std::vector<Range>& GetServerKeyRanges(); /**
* \brief 回调函数的别名。
*/
using Callback = std::function<void()>; /**
* \brief 向系统注册一个回调函数,在 Finalize() 方法完成后被调用。
*
* 以下代码是等价的:
* \code {cpp}
* RegisterExitCallback(cb);
* Finalize();
* \endcode
*
* \code {cpp}
* Finalize();
* cb();
* \endcode
* \param cb 回调函数。
*/
void RegisterExitCallback(const Callback& cb) {
exit_callback_ = cb;
} /**
* \brief 从 Worker 编号映射到节点编号。
* \param rank the worker rank
*/
static inline int WorkerRankToID(int rank) {
return rank * 2 + 9;
} /**
* \brief 从 Server 编号映射到节点编号。
* \param rank the server rank
*/
static inline int ServerRankToID(int rank) {
return rank * 2 + 8;
} /**
* \brief 从节点编号映射到 Server/Worker 编号。
* \param id 节点编号。
*/
static inline int IDtoRank(int id) {
return std::max((id - 8) / 2, 0);
} /** \brief 返回 Worker 数量。 */
int num_workers() const { return num_workers_; } /** \brief 返回 Server 数量。 */
int num_servers() const { return num_servers_; } /** \brief 返回节点在所属分组的编号。
*
* 每个 Worker 都有唯一的编号,范围是 [0, NumWorkers())。Server 也是如此。
* 该方法仅当 Start() 方法被调用后有效。
*/
int my_rank() const { return IDtoRank(van_->my_node().id); } /** \brief 是否是 Worker 节点。 */
int is_worker() const { return is_worker_; } /** \brief 是否是 Server 节点。 */
int is_server() const { return is_server_; } /** \brief 是否是 Scheduler 节点。 */
int is_scheduler() const { return is_scheduler_; } /** \brief 返回日志级别。 */
int verbose() const { return verbose_; } /** \brief 是否是可恢复的节点。 */
bool is_recovery() const { return van_->my_node().is_recovery; } /**
* \brief 屏障。
* \param node_id 要同步的节点组的编号。
*/
void Barrier(int customer_id, int node_group); /**
* \brief 处理控制信息,由持有的 Van 实例调用。
* \param recv 收到的消息。
*/
void Manage(const Message& recv); /**
* \brief 更新心跳记录。
* \param node_id 节点编号。
* \param t 心跳时间戳。
*/
void UpdateHeartbeat(int node_id, time_t t) {
std::lock_guard<std::mutex> lk(heartbeat_mu_);
heartbeats_[node_id] = t;
} /**
* \brief 获取在过去 t 秒内未发送心跳的所有节点。
* \param t 以秒为单位的超时。
*/
std::vector<int> GetDeadNodes(int t = 60);
}

Van 类

/**
* \brief Van 类负责发送消息到远端节点。
*
* 如果环境变量 PS_RESEND 被设置位 1,那么在 PS_RESEND_TIMEOUT 毫秒后没有收到 ACK 消息的情况下,Van 实例会重发消息。
*/
class Van {
public:
/**
* \brief 实例化 Van 类。
* \param type zmq、socket等。
*/
static Van *Create(const std::string &type); /** \brief 空的构造器。使用 Start() 方法来真的启动。
Van() {} /**\brief 空的析构器。使用 Stop() 方法类真的停止。
virtual ~Van() {} /**
* \brief 启动 Van。
*
* 必须先调用该方法,才能调用 Send() 方法。
*
* 该方法初始化到所有节点的连接,启动接受消息的线程。
* 如果收到了控制信息,交给 PostOffice::Manage() 方法处理。否则,交给相应的应用处理。
*/
virtual void Start(int customer_id); /**
* \brief 发送一个消息。线程安全。
* \return 返回发送的字节数。如果发送失败,返回 -1。
*/
int Send(const Message &msg); /**
* \brief 返回所在的节点。
*/
inline const Node &my_node() const {
CHECK(ready_) << "call Start() first";
return my_node_;
} /**
* \brief 停止 Van。
* 停止接受消息的线程。
*/
virtual void Stop(); /**
* \brief 获取下一个可用的时间戳。线程安全。
*/
inline int GetTimestamp() { return timestamp_++; } /**
* \brief 是否可以发送消息。线程安全。
*/
inline bool IsReady() { return ready_; }
}

PS Lite - 源码解读的更多相关文章

  1. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  2. AFNetworking 3.0 源码解读(七)之 AFAutoPurgingImageCache

    这篇我们就要介绍AFAutoPurgingImageCache这个类了.这个类给了我们临时管理图片内存的能力. 前言 假如说我们要写一个通用的网络框架,除了必备的请求数据的方法外,必须提供一个下载器来 ...

  3. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager

    做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一 ...

  4. AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization

    这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...

  5. AFNetworking 3.0 源码解读(四)之 AFURLResponseSerialization

    本篇是AFNetworking 3.0 源码解读的第四篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3 ...

  6. AFNetworking 3.0 源码解读 总结

    终于写完了 AFNetworking 的源码解读.这一过程耗时数天.当我回过头又重头到尾的读了一篇,又有所收获.不禁让我想起了当初上学时的种种情景.我们应该对知识进行反复的记忆和理解.下边是我总结的 ...

  7. AfNetworking 3.0源码解读

    做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一 ...

  8. jQuery.Callbacks 源码解读二

    一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...

  9. Jfinal-Plugin源码解读

    PS:cnxieyang@163.com/xieyang@e6yun.com 本文就Jfinal-plugin的源码进行分析和解读 Plugin继承及实现关系类图如下,常用的是Iplugin的三个集成 ...

随机推荐

  1. Docker与k8s的恩怨情仇(二)—用最简单的技术实现“容器”

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 上次我们说到PaaS的发展历史,从Cloud Foundry黯然退场,到Docker加冕,正是Docker& ...

  2. 温故而知新--day5

    温故而知新--day5 ip地址 IP是英文Internet Protocol的缩写,意思是"网络之间互连的协议",也就是为计算机网络相互连接进行通信而设计的协议.当多个设备要进行 ...

  3. Golang编写Windows动态链接库(DLL)及C调用范例

    一.准备. 1.GoLang在1.10版本之后开始支持编译windows动态链接库,可以打开命令行工具使用go version 查看自己的go版本. 2.你的电脑上需要gcc,如果没有的话[点击这里] ...

  4. linux 下安装 docker 环境

    一分钟了解 Docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源.Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然 ...

  5. excel函数提取身份证出生日期,分离日期时间的日期和时间

    1.提取身份证出生日期 =1*TEXT(MID(H13,7,8),"0-00-00")用MID函数提取表示日期的位数,再用text函数转换为格式1998-6-21格式的文本,再通过 ...

  6. Qt之先用了再说系列-串口通讯(单串口单线程)

    QT 串口通讯(单串口单线程) 串口通讯在我们写程序的时候或多或少会用到,借此在这记录一下QT是如何使用串口来通讯的.本次先侃侃在单线程下使用1个串口来通讯过程.好了,废话不多说,直接看步骤,我们的宗 ...

  7. Redis 过期时间解析

    文章参考:<Redis 设计与实现>黄建宏 设置过期时间 通过 EXPIRE 或者 PEXPIRE 命令,客户端可以以秒或毫秒精度为数据库中的某个键设置生存时间 TTL (Time To ...

  8. 安装eclipse及Helloworld体验

    准备工作 如果没有配置java环境变量的请移步:https://www.cnblogs.com/lhns/p/9638105.html 下载eclipse 网址:https://www.eclipse ...

  9. Robotframework学习笔记之—Rrobotframework运行报错“command: pybot.bat --argumentfile”

    Rrobotframework运行报错"command: pybot.bat --argumentfile" 解决方案: 1.可能是缺失文件: 1.1.检查python安装目录下的 ...

  10. C语言字符串处理库函数大全(转)

    一.string.h中字符串处理函数 在头文件<string.h>中定义了两组字符串函数.第一组函数的名字以str开头:第二组函数的名字以mem开头. 只有函数memmove对重叠对象间的 ...