​ 常见的服务器模型有多进程模型,多线程,IO多路复用,协程等模型。sonic的核心守护进程orchagent采用的是IO多路复用模型,早期的sonic采用的是select实现多路复用,后面的版本采用的是epoll。使用select(跟多路复用的select名字一样)类对底层进行了封装,屏蔽了差异。

class Selectable

事件基类,描述了epoll事件,可以是读,写,异常等事件。该结构对通用epoll事件进行了封装,真实事件通过该类派生出来,比如redis数据库事件:class RedisSelect : public Selectable;netlink事件:class NetLink : public Selectable;通知:class NotificationConsumer : public Selectable,orch执行单元:class Executor : public Selectable,定时器:class SelectableTimer : public Selectable等。

class Selectable
{
public:Selectable(int pri = 0) : m_priority(pri),m_last_used_time(std::chrono::steady_clock::now()) {lastusedsequence = g_lastusedsequence++;}virtual ~Selectable() = default;/* return file handler for the Selectable */virtual int getFd() = 0;/* Read all data from the fd assicaited with Selectable */virtual void readData() = 0;/* true if Selectable has data in its cache */// 判断是否还有数据,如果有放入就绪事件setvirtual bool hasCachedData(){return false;}/* true if Selectable was initialized with data */// 判断是否需要读取初始数据virtual bool initializedWithData(){return false;}/* run this function after every read */// 更新事件数virtual void updateAfterRead(){}int getPri() const{return m_priority;}private:friend class Select;//友元类为Select// only Select class can access and update m_last_used_timestd::chrono::time_point<std::chrono::steady_clock> getLastUsedTime() const{return m_last_used_time;}// 最后使用序列号unsigned long getLastUsedsequence() const{return lastusedsequence;}// 跟新最后使用序列号void updateLastUsedTime(){m_last_used_time = std::chrono::steady_clock::now();lastusedsequence = g_lastusedsequence++;}// 优先级,实现基于优先级调度int m_priority; // defines priority of Selectable inside Select// higher value is higher prioritystd::chrono::time_point<std::chrono::steady_clock> m_last_used_time;unsigned long lastusedsequence;//上次使用序列号static unsigned long g_lastusedsequence;//全局基准序列号,用于对同优先级业务进行公平调度
};

class Select

class Select
{
public:Select();~Select();/* Add object for select 给epoll添加一个事件 */void addSelectable(Selectable *selectable);/* Remove object from select 删除一个epoll事件 */void removeSelectable(Selectable *selectable);/* Add multiple objects for select 添加多个epoll事件 */void addSelectables(std::vector<Selectable *> selectables);enum {//返回的事件类型OBJECT = 0,ERROR = 1,TIMEOUT = 2,};//执行epoll int select(Selectable **c, unsigned int timeout = std::numeric_limits<unsigned int>::max());int select(std::vector<Selectable *> &vc, unsigned int timeout = std::numeric_limits<unsigned int>::max());private://epoll事件比较函数,通过该函数实现事件的优先级struct cmp{bool operator()(const Selectable* a, const Selectable* b) const{/* Choose Selectable with highest priority first */if (a->getPri() > b->getPri())return true;else if (a->getPri() < b->getPri())return false;/* if the priorities are equal *//* use Selectable which was selected later */if (a->getLastUsedsequence() < b->getLastUsedsequence())return true;else if (a->getLastUsedsequence() > b->getLastUsedsequence())return false;/* when a == b */return false;}};//epoll轮询函数int poll_descriptors(Selectable **c, unsigned int timeout);int poll_descriptors(std::vector<Selectable *> &vc, unsigned int timeout);int m_epoll_fd;//epoll句柄std::unordered_map<int, Selectable *> m_objects;//监听的事件句柄与其对应的selectable之间的关系std::set<Selectable *, Select::cmp> m_ready;//已经就绪的事件集合,提供了比较函数,从而实现优先级调度
};

Select::Select()

Select::Select()
{m_epoll_fd = ::epoll_create1(0);//创建epoll句柄if (m_epoll_fd == -1){std::string error = std::string("Select::constructor:epoll_create1: error=("+ std::to_string(errno) + "}:"+ strerror(errno));throw std::runtime_error(error);}
}

Select::~Select()

Select::~Select()
{(void)::close(m_epoll_fd);
}

void Select::addSelectable(Selectable *selectable)

void Select::addSelectable(Selectable *selectable)
{const int fd = selectable->getFd();if(m_objects.find(fd) != m_objects.end())//已经添加了该事件,退出{SWSS_LOG_WARN("Selectable is already added to the list, ignoring.");return;}m_objects[fd] = selectable;if (selectable->initializedWithData())//是否已经有数据可读,读出已有的数据{m_ready.insert(selectable);}//添加可读事件struct epoll_event ev = {.events = EPOLLIN,.data = { .fd = fd, },};int res = ::epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, fd, &ev);if (res == -1){std::string error = std::string("Select::add_fd:epoll_ctl: error=("+ std::to_string(errno) + "}:"+ strerror(errno));throw std::runtime_error(error);}
}

void Select::removeSelectable(Selectable *selectable)

void Select::removeSelectable(Selectable *selectable)
{const int fd = selectable->getFd();m_objects.erase(fd);m_ready.erase(selectable);//从epoll中删除事件int res = ::epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, fd, NULL);if (res == -1){std::string error = std::string("Select::del_fd:epoll_ctl: error=("+ std::to_string(errno) + "}:"+ strerror(errno));throw std::runtime_error(error);}
}

void Select::addSelectables(vector<Selectable *> selectables)

void Select::addSelectables(vector<Selectable *> selectables)
{for(auto it : selectables)//添加多个事件{addSelectable(it);}
}

int Select::poll_descriptors(......)

提取一个就绪事件

int Select::poll_descriptors(Selectable **c, unsigned int timeout)
{int sz_selectables = static_cast<int>(m_objects.size());std::vector<struct epoll_event> events(sz_selectables);int ret;//阻塞等待事件发生,发生错误或者被中断打断则继续监听,发生事件则执行事件do{ret = ::epoll_wait(m_epoll_fd, events.data(), sz_selectables, timeout);}while(ret == -1 && errno == EINTR); // Retry the select if the process was interrupted by a signalif (ret < 0)return Select::ERROR;//遍历每一个发生的事件for (int i = 0; i < ret; ++i){int fd = events[i].data.fd;Selectable* sel = m_objects[fd];//获取事件描述符sel->readData();//读取数据m_ready.insert(sel);//插入就绪集合}//存在就绪事件if (!m_ready.empty()){auto sel = *m_ready.begin();*c = sel;m_ready.erase(sel);// we must update clock only when the selector out of the m_ready// otherwise we break invariant of the m_ready// 更新该事件的使用时间,使用事件会作为事件优先级进行使用,越频繁的优先级越低,从而避免同优先级的事件// 饿死sel->updateLastUsedTime();// 有数据,依然放入已经就绪集合if (sel->hasCachedData()){// reinsert Selectable back to the m_ready set, when there're more messages in the cachem_ready.insert(sel);}// 对数据进行刷新,如果该句柄只发生了一次事件,那么这里会进行减1,下次m_ready中将不会存在该sel。// 仔细分析了sonic的selectable的实现,这里是有bug的,会造成大量的空转。sel->updateAfterRead();return Select::OBJECT;}return Select::TIMEOUT;
}

int Select::poll_descriptors(std::vector<Selectable *> &vc, unsigned int timeout)

提取多个就绪事件,该函数是在上面的函数的基础上的改进。只提取一个事件将会造成"饿死和胀死"的问题。由于m_ready是有序队列,对于高优先的事件总是会被优先提取,如果高优先级的事件依赖于低优先级事件的话,会造成高优先级的业务一直被调度,但是缺少依赖条件而不能执行业务,低优先级业务总是得不到调度,形成死锁问题。同时提取所有就绪事件可以解决高低优先级死锁问题。

int Select::poll_descriptors(std::vector<Selectable *> &vc, unsigned int timeout)
{int sz_selectables = static_cast<int>(m_objects.size());std::vector<struct epoll_event> events(sz_selectables);int ret;do{ret = ::epoll_wait(m_epoll_fd, events.data(), sz_selectables, timeout);}while(ret == -1 && errno == EINTR); // Retry the select if the process was interrupted by a signalif (ret < 0)return Select::ERROR;for (int i = 0; i < ret; ++i){int fd = events[i].data.fd;Selectable* sel = m_objects[fd];sel->readData();m_ready.insert(sel);}auto iter = m_ready.begin();while(iter !=m_ready.end()){auto sel = *iter;vc.push_back(sel);iter = m_ready.erase(iter);sel->updateLastUsedTime();}for(auto se:vc){if (se->hasCachedData()){m_ready.insert(se);}se->updateAfterRead();}if(!vc.empty()){return Select::OBJECT;}return Select::TIMEOUT;
}

int Select::select(Selectable **c, unsigned int timeout)

int Select::select(Selectable **c, unsigned int timeout)
{SWSS_LOG_ENTER();int ret;*c = NULL;if (timeout == numeric_limits<unsigned int>::max())timeout = -1;/* check if we have some data */ret = poll_descriptors(c, 0);/* return if we have data, we have an error or desired timeout was 0 */if (ret != Select::TIMEOUT || timeout == 0)return ret;/* wait for data */ret = poll_descriptors(c, timeout);return ret;
}

int Select::select(std::vector<Selectable *> &vc, unsigned int timeout)

int Select::select(std::vector<Selectable *> &vc, unsigned int timeout)
{SWSS_LOG_ENTER();int ret;if (timeout == numeric_limits<unsigned int>::max())timeout = -1;/* check if we have some data */ret = poll_descriptors(vc, 0);/* return if we have data, we have an error or desired timeout was 0 */if (ret != Select::TIMEOUT || timeout == 0)return ret;/* wait for data */ret = poll_descriptors(vc, timeout);return ret;}

sonic orch调度系统(1)----select相关推荐

  1. 【Java7】练习:选角色,挑苹果,员工类,换心脏,斗地主,发工资,客户信息管理软件,开发团队调度系统

    文章目录 1.玩家选择角色:return new 2.人工挑苹果:只一个接口CompareAble 3.员工类接口:implements Comparator 4. 医生帮换心脏:Organ类doWo ...

  2. 面向大数据与云计算调度挑战的阿里经济体核心调度系统

    编者按 伏羲(Fuxi)是十年前最初创立飞天平台时的三大服务之一(分布式存储 Pangu,分布式计算 MaxCompute,分布式调度 Fuxi),当时的设计初衷是为了解决大规模分布式资源的调度问题( ...

  3. 当我们在聊「开源大数据调度系统Taier」的数据开发功能时,到底在讨论什么?

    原文链接:当我们在聊「开源大数据调度系统Taier」的数据开发功能时,到底在讨论什么? 课件获取:关注公众号__ "数栈研习社",后台私信 "Taier"__ ...

  4. 工作流调度系统Apache DolphinScheduler介绍和设计原理

    1 概述 Apache DolphinScheduler(目前处在孵化阶段)是一个分布式.去中心化.易扩展的可视化DAG工作流任务调度系统,其致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数 ...

  5. 一个著名的调度系统是怎么设计的?

    实习生张大胖 这是个代码写得很烂的电商系统,只要运行一段时间,服务器就会出现Out Of Memory. 别人都忙得四脚朝天,于是实习生张大胖被抓了壮丁去研究为什么会出现OOM. 刚入行的张大胖技术水 ...

  6. 可视化指挥调度系统_如何通过视力调度使预订系统现代化

    可视化指挥调度系统 This article was sponsored by Acuity Scheduling. Thank you for supporting the sponsors who ...

  7. 027 大数据之Azkaban调度系统

    1.Azkaban 3.0 中文文档 大数据平台 -- 调度系统之Azkaban azkaban-web和azkaban-exec的一键启动和关闭(shell脚本) 解决 Azkaban Execut ...

  8. 如何从零开始设计与开发一款通用模型预测调度系统 | 干货分享

    机器学习模型从训练导出到生成环境部署,这个过程中涉及大量工作,会面临着各种问题与挑战,比如不断丰富的业务场景,系统需要负载种类繁多的神经网络,预测任务不均匀等,然而企业拥有的计算资源(如GPU个数)是 ...

  9. agv调度matlab程序,一种分布式AGV调度方法及调度系统与流程

    技术领域 本发明涉及AGV调度技术领域,尤其是一种分布式AGV调度方法及调度系统. 背景技术: 目前,物流.仓库等需要大量货品搬运的情形,开始采用多个自动导引运输车(英文简称AGV)协同工作,无需人工 ...

最新文章

  1. 课外知识----浏览器存储技术
  2. Java包装类中的equals方法
  3. Hive partition prune Failed
  4. linux php源码安装mysql_linux源码安装mysql5.7
  5. 解决小程序背景图片在真机上不能查看的问题
  6. 对JDBC进行简单的封装
  7. LeetCode-Sum Root to Leaf Numbers
  8. 整理一下CCF推荐期刊会议(A类)
  9. html打开后繁体字怎么变成规范,对HTML标准的思考 - 记解决H5随机显示简繁体汉字问题...
  10. 最新互联网架构师视频教程+源码20G
  11. 未知地区的探索与猜想
  12. 2015 年度新增开源软件排名TOP100
  13. python项目-Python 的练手项目有哪些值得推荐?
  14. Android多线程理解
  15. 苹果IOS的ANCS服务
  16. vscode开发中绝对让你惊艳的插件!!!(个人在用) 持续更新。。。。
  17. 期货反向跟单犯法吗?
  18. Github 上 lux 下载神器的安装及使用教程
  19. 联想计算机搜不到mfp,电脑检测不到联想LJ2200L打印机
  20. mysql分组查询学生平均年龄_那些年我们一起做过的[分组查询]_MySQL

热门文章

  1. 零基础学习Python3——Python 安装
  2. html超链接 新弹出窗口 和字体颜色
  3. MySQL数据库程序设计——成绩管理系统
  4. 沙子是如何变成Micro LED模组。
  5. 元宇宙+区块链,会是互联网的终极形态吗?
  6. 计算机桌面上的材料怎么显示,怎样在电脑桌面上显示便签
  7. mysql bigd_mysql 5.7 配置多实例 — mysqld_multi 方式
  8. 关于String类中的类型转换一些方法
  9. 2014年春节到香港旅游攻略
  10. 抖音广告助手是干什么的?在文章中为大家总结了4点