Introduction
本人现在是大四生。
该博客主要记载以下文章:
编程或学习的思考,总结和讨论
学习笔记
自己项目的一些架构,设计或灵感
一些文档的阅读笔记
…
最近感兴趣的方面是分布式系统,编译器设计。
最近(正在)写的项目是mmkv,感兴趣的话可以去github页面看README了解。可能的话,希望你也能为该项目贡献代码。
高效的StrAppend和StrCat实现
前言其实实现个StrAppend和StrCat早就有所考虑了,不过近来的编码没有这方面需求(其实有的,不过不是热点问题),所以也就作罢。这方面其实早就听闻absl有string util库,看了一下文档,有类似的设施:StrAppend()和StrCat()。不过为了两个函数,而引入个第三方库,未免有点头大。因此我还是打算实现自己的版本。只是出乎我意料的是,我的实现似乎还优于absl的。
正确的StrAppend姿势对于一个cpp新手来说,可能会通过下面这种方式进行append:12string s = ...;s += s1 + s2 + s3 + ...;稍微对运算符重载了解的想必都知道每个运算符会生成一个临时对象,因此上述表达式等效于:12s += ((s1 + s2) + s3) + ...; ^ ^因此一些教材或是论坛回答会建议用多语句的append替代:1234s += s1;s += s2;s += s3;s += ...;不否认,这样避免了临时对象的生成,但是仍不是最优的写法。我们可以预分配目标字符串的内存空间,从而避免多次append带来的多次内存重分配。1s ...
讨论Load balancing中的session persistence
前言这段时间一直在思考实现一个针对HTTP协议的LB该考虑哪些要素。其中一个特性令我深思,那就是会话持久(session persistence)该如何保证?之所以关注该特性,那必然是因为缓存的信息多是和用户、业务直接相关的,一旦缓存失效,那么就会导致用户体验下滑,比如莫名其妙地回到了登录界面;另外,再次缓存也会导致对性能等因素造成负面影响。总之,各种意义上来说,不能说是个可以忽视的特性。
一致性哈希要实现均衡负载中会话持久,单纯地依赖于任何特定均衡算法(bancing algorithm),我觉得是不可能的。即使是一致性哈希(consistent hashing),在集群增加或移除节点时,也终究会导致部分节点被重定向,这样下一次的请求会发送到不同于原来节点的新节点上去,这样原来的节点上的缓存信息也就失效了。假设我们硬是要用一致性哈希的话,那要应对缓存失效可能就需要一个app server将session缓存数据转移到其他app server上去,而这对app server又做出了新要求,即耦合了app server的代码。显然,对于不同的app server来说这就是个折磨,相当于自 ...
delete 不完全类型对象
前言在看一些开源代码,会发现delete可能会先判断是否为不完全类型:1234...typedef char MustCompleteType[sizeof(T) == 0 ? -1 : 1];delete obj;...这是有必要的,因为delete不安全类型并不算error而是waring。这篇博客就是讨论这个。
标准是怎么说的
If the object being deleted has incomplete class type at the point of deletion and the complete class has anon-trivial destructor or a deallocation function, the behavior is undefined. — N3337 3.4.5 Delete因此delete不完全类型可能会导致crash,也可能仅仅是单纯的不调用析构函数罢了。但无论如何,这都是应该避免的。
避免手法显然,我们需要的是编译时断言,因为一个类型是否为完全类型是编译时确定的。上面展示的是一种做法,另外一种做法是利用C++11的静 ...
实现自己的Closure以使rpc的回调兼容所有可调用对象
前言虽然kanon早就实现了protobuf的编解码器并在此基础上实现了基于protobuf的rpc模块以便进行rpc通信。但是我一直都挺拒绝使用这玩意,因为google::protobuf::RpcChannel提供的CalllMethod()签名如下:12345void CallMethod(MethodDescriptor const *method, RpcController *controller, Message const *request, Message *response, Closure *done);然而,protobuf实现的Closure的派生类并不是类似std::function<>那样可以包裹任何可调用对象(callable),想必是C++11之前的产物,因为11已经有lambda expression,std::bind,std::function可以包装任何回调了。如果使用protobuf::protobuf::New ...
对Service Discovery with router tier的思考
前言最近,在思考Load Balancer(LB)和Configuration Controller的区别,最后根据《DDIA》中提到的关键词搜到的资料总算是明确了两者的一些优缺点(大概),也验证了我的一些想法,它们都属于service discovery问题的一种解决方案。
Service discovery所谓服务发现,根据我的理解,它就是指一个客户端接入整个集群,它怎么找到应该提供给它服务的服务器,即哪个节点它应该连接以至于服务内容是正确的或是对应的。比如,对于kv服务,如果采用集群形式提供服务,那么可能采取哈希键的方式获取到具体的节点,然后之后对于该键的操作都应该连接该节点(具体实现会更复杂)。
这个问题的解决影响整个集群的可用性,因此设计集群估计是避不开的。
以下我想讨论的主要是服务发现中的一种方案:带有路由层(router-tier)的集群更细化的方案思考。
Load Balancer根据nginx文档可以了解到均衡负载器(以下可能称呼为LB)的作用主要是将客户端的请求转发根据均衡负载算法转发给后端的(提供服务的)服务器,从而保证所有服务器并不会工作过载(overwork) ...
COS333 assignment1 -- glob
前言该博客记录的是COS333的assignment1,该任务是要我改写TPOP(The practive of programming)中第9章第2节的处理正则表达式的代码,以符合新的匹配规则:glob)。根据维基百科来看,glob最早是应用于unix上的一个命令,取自global的缩写,最主要的作用就是通过通配符(wildcard)拓展文件名列表。当然,要我们实现的好像并不是完整的glob,而是一部分子集规则:
?: 任意单个字符
*: 任意0个或多个字符
\: 对特殊字符进行转义,转义符后没有字符算语法错误
$和^并不是特殊字符
匹配的范围是整个输入字符串,可以认为是正则表达式的^input$
思路根据原有代码的提示不难得出它解析正则表达式的思路是递归解析。至于为什么采用递归而不是迭代是因为通过分析递归的roadmap发现它们存在相互调用且是根据条件切换的。更好的方法应该是构造NFA来解析,但是在glob表达式不长的情况下,递归是足够满足性能需求的。比较麻烦处理的是转义规则的处理,这里我是通过一个变量记录了是否遇见了转义符,其实如果有记录长度的变量会更好办,但是为了这么一个目 ...
base64 encoder & decoder
前言base64 encode & decode是COS333的assignment 3,根据其提示,通过翻阅rfc2045 section 6.8和wikipedia编写了base64的解编码器。
什么是base64base64是一种将原生二进制数据编码为64个可打印ASCII码的编码格式(encoding format)。因为是base256转化为base64,所以大小相比原来膨胀了1/3,不过一般来说是可以接受的。
为什么需要base64作为大小膨胀的代价,base64带来的好处在于:
兼容上古时期(1990’s)的各种系统的encoding标准,控制字符和其他非打印字符可能被误解读
兼容上古时期的文本协议,不支持base256,比如早期的SMTP,只支持(关注)7位ascii字符
对于不是8 bit clean的系统,其第8位可能被置为0,因此破坏了二进制数据
除此之外,现在web开发中有的时候会将图片等二进制资源塞进json等数据格式中,那么需要图片转化为字符,base64是一种满足该需求的编码格式。
编码(encode)base64说白了就是原来的base256 ...
Hexo butterfly 4.3.1 背景透明度设置
前言通过搜索引擎(baidu,google)找到了一些线索:背景设置透明需要自己通过diy css来支持该功能。通过在butterfly的github issues中作者对相关问题的回答来看也确实是这样。但是关键在于网上流传的css已经不适用于该版本的了。换言之,需要diy符合该版本的css。这对我一个没有前端知识的小白来说,略显困难,但我通过浏览器的开发者工具锁定了文章页的样式,最终得到了符合的结果。
具体做法在/theme/butterfly/source/css创建css文件,假设命名为user.css,内容如下:1234567.layout > div:first-child:not(.recent-posts),#recent-posts > .recent-post-item,#aside-content .card-widget,.layout > .recent-posts .pagination > *:not(.space) { /* 第四个参数表示透明度,越小越透明 */ background: rgba(239,239,23 ...
对于重载函数的参数类型声明的思考
前言随着C++11的到来,要考虑重载函数的参数类型增多了:右值引用以支持移动,通用引用以支持完美转发等。我们为了更高效的支持拷贝或移动,需要考虑支持左右值(我这里不细分纯右值和亡值)。
对于确定的类型通用引用 + 显式实例化通过通用引用和完美转发可以支持左右值:1234template<typename U>void f(U &&value) { auto s = std::forward<U>(value);}但这个比较麻烦的一点在于依赖于模板,也就是说U是个确定类型的话,你定义也得写在头文件中。为了避免这一点,通过显式实例化可以分离实现到源文件中:1234567891011121314// In a.hstruct A { template<typename T> void f(T &&v);}// In a.cpptemplate<typename T>void A::f(T &&v) { auto val = std::for ...