参加了个阿里的kv数据库比赛,接触到持久化内存的概率,到现在对这里理解的也不是太深入,只管总结一下。看了官方的书,还有一些代码和官方视频,但是为了参加比赛,还是觉得研究一下代码。初步看了看发现能在比赛上优化的地方还挺多的,所以决定慢慢总结和移植一下。
持久化内存(Persistent Memory)我看网上好像概念已经老早就有了,我是第一次知道,也记不住讲不清。总的来说就是可以掉电不丢数据的内存,是嫌ssd慢了,又出来一个算是ssd和内存的中间层。还有两种模式,可以当普通内存用,相当于扩展普通内存的容量。或者当持久内存用,可以保证掉电不丢数据和快速的读写速度。
libpmem是intel开发的持久化内存开发组件(Persistent Memory Development Kit)里的一个库,属于底层库,libpmemobj等库都是在这基础上开发的。比赛用到,基本不考虑libpmemobj这库,集成太厉害了,libpmem我大体看了代码发现也可以修改移植,能优化不少。而且因为我c语言经验不多,看了源码后发现能学很多东西。所以决定阅读总结加移植代码。
大体的使用思路就是,基于系统调用mmap进行pmem的进程空间地址的映射,这里是内核原生支持了。所以这玩意应该出了很久了,才刚听说,感觉阿里应该属于用的比较早的。之后就跟正常使用内存一样了,而这些操作都是在用户空间,所以效率理论上还有优势,虽然本身速度赶不上内存。持久化操作需要将cpu cache里的数据踢出到内存(evict),刷新到持久内存上。
基本情况就这样,下边看几个基础文件。学到很多代码
core/util.h util.c
这俩都是常用函数集合
#define force_inline __attribute__((always_inline)) inline
#define NORETURN __attribute__((noreturn))
#define barrier() asm volatile("" ::: "memory")
第一个从名字就看出来是强制函数inline,第二个是有时候写的分支没有返回时编译器会有报错,这个可以告诉编译器不要报错。第三个是内存栅栏。
typedef uint64_t ua_uint64_t __attribute__((aligned(1)));
能够指定最少字节对齐数,受连接器限制,不会超过连接器大小。感觉没啥用,但是也可能以后用上,学到东西了。
util_setbit, util_clrbit这个是位操作,这个是会的
util_is_pow2, return v && !(v & (v - 1)); 判断是否是2的幂
__builtin_ctz,__builtin_clz,这个是判断一个数,从开头或者从结尾有多少个零的,厉害了。
其他的就没啥了,看看util.c
util_is_zeroed检查内存为0,应该用不到,记录下。util_checksum_compute,这是是计算一块内存的checksum,已移植,不知道会不会比hash快,这个应该比hash准确,但是比赛还是讲究速度,到时候试试。算法好像是Fletcher64。
valgrind好像能模拟cpu环境,调试程序的,好像书里有写,没太看内容,先记录。
Mmap_align好像用来分配对齐的,这里不知道干啥的,先跳过记录。linux下直接分配的Pagesize = (unsigned long) sysconf(_SC_PAGESIZE)
util_concat_str连接字符串,没用记录.util_localtime获取时间,没用记录
其他的基本用不上了,主要看书看到原理的地方,发现checksum相关内容,有用到,就搜了一下源码,看到这些代码。
Read more...
Archive for 算法-编程
R语言devtools包和单元测试testthat包
devtools包能够方便在开发R语言包时,测试,文档生成,安装包等操作。
testthat包是单元测试的包,这里要写单元测试了。
devtools的安装需要提前安装一些依赖,不然安装会报错,我的是ubuntu系统,需要安装一下依赖
apt install libxml2-dev libcurl4-openssl-dev
安装完这俩软件,再安装就可以了,具体是否依赖其他软件就不清楚了,我这里是少这俩,官方文档也不太友好。
我是先创建的package在安装的devtools,发现现在没有好的方法添加test文件了,我是使用的testthis包进行创建的,这个三个包都是一个公司出的,testthis包的内容没看全,看起来是devtools所有相关功能都是在这里实现的。
use_test()
可以安装目录文件创建tests文件及内容,还有NAMESPACE文件依赖的修改等
可以使用use_test('hello.R')生成制定文件的test文件,我看文件命名规则基本生成test-hello.R,context为hello。
test_that("multiplication works", {
expect_equal(2 * 2, 4)
})
执行test()或者使用RStudio里的build菜单执行单元测试
Read more...
R语言使用RMariaDB连接数据库获取数据
网上最常用的R语言连接数据库的包是RMySQL,但是我看RMySQL推荐使用RMariaDB,RMySQL以后会不在维护。所以使用RMariaDB了,这个使用上应该没啥区别,因为他们都使用了DBI包,规范了数据库接口的定义。
结合上一篇讲全局变量的问题,我存在了options里代码如下
db_config <- getOption("db_config")
con <- dbConnect(RMariaDB::MariaDB(), dbname=db_config$db, username=db_config$user, password=db_config$password, host=db_config$host)
print(con)
print(dbListTables(con))
dbDisconnect(con)
Read more...
R语言自定义包编写安装
包初始化创建我是用的rstudio,创建的r package项目。
然后可以build菜单选择build source package,右侧的build窗口可以check,install,非常快的点击就完成了
也可以用命令做
R CMD build tpk
R CMD CHECK
R CMD INSTALL tpk
这里我傻了吧唧,命令行操作的时候, install 后面跟了个tar包全名,导致后边用install.package时候也是用的全名,导致查错误也每个结果。搞了半天发现名字不对。
Read more...
R语言包中全局变量、常量问题
没有系统学过r的坏处体现出来了,现在想到什么就要去搜什么。
常量好像在R中是不存在的,sof上看到一个例子,但是没啥用,还不如直接注释声明。
a <- 1
lockBinding("a", globalenv())
a <- 2
Error: cannot change value of locked binding for 'a'
非包中全局变量,可以使用<<-来保证局部变量引用的全局变量,但包内的不知道。通过查找,基本实现方式一个是通过myenv <- new.env()来实现,这个返回类型为environment,还没有细看。
还有一种实现方式是使用.onLoad,在包加载的时候可以调用的一些列函数。一般声明在zzz.R文件中,这个文件名是约定俗成的。
Read more...
R语言,项目目录设计,和一些代码规范
要写项目就需要想到这些,因为没有经验,只能网上找一些项目或者搜一些规范。大部分都是package的项目,所以我找文章找到一些规范。
https://www.r-bloggers.com/2018/08/structuring-r-projects/
这篇文章介绍比较全面,目录结构大部分按他这个来了。其中对于library(package)载入包的情况进行了说明,可以使用package::function(arg1, arg2, ...)来调用不常用包的函数,这个方式的好处是不会打乱命名空间,除非知道这些包没有冲突,不然确实出现问题不一定好排查。(提前看文章避免了坑)
还有一些代码规范,但是我应该之会借鉴一部分变量命名方式,像参数空格这种我就不准备用了。
http://stat405.had.co.nz/r-style.html
然而查了一大顿之后,我决定还是把项目组织成R语言 package的目录结构,因为那个比较规范,也有文档测试啥的目录,很清晰。
具体需要参考https://cran.r-project.org/doc/manuals/R-exts.pdf官方文档了
Read more...
R语言不明确的作用域机制和force函数的作用
刚研究了log4r的使用,就想着也不是什么大包,自己也没写r项目的经验,看看源码学习一下吧。然后在appender里看file_appender的时候,看到了一个force函数。
本能的去Rstudio上查了一下文档,因为软件看文档比终端好一点。然后发现这个不简单啊。
幸好之前写过python对这种坑机制有了解,感觉上R与Python很多地方相似。
安装文档说明,R函数的参数在定义的闭包中使用的时候,比如在循环和apply函数的调用,会导致从变量作用域中获取这些参数变量,也就是所谓的惰性求值。虽然我现在看的文档中还没有涉及变量作用域的问题,感觉在R中应该和在Python中是差不多的,循环体是不具有变量作用范围的保证的。而force函数能保证这个参数被执行求值,从而保证闭包里作用域里的变量的值的变化。
?force文档里有个例子很好的说明了这一点。
Read more...
R语言日志包log4r
看log4r的名字就感觉跟log4j有渊源啊,其中还要好多个日志包,最后决定log4r和logging里边一个,logging是仿的python日志模块的包,但是我最后没选这个,主要是因为接口设计的不太好,就选择了log4r。
安装包
install.packages("log4r")
使用
library(log4r)
logger <- logger("INFO", appenders = file_appender("log/base.log"))
info(logger, "info")
debug(logger, "debug")
error(logger, "error")
使用的时候有几个点需要注意,
我目前安装最新的版本是 0.3.2,但是?log4r的文档版本是0.2,然后我用那个文档里的老接口和github上的新接口混用,导致日志文件没更新成功。后来才意识到文档不对。
日志文件在输出第一条日志的时候才会创建。
Read more...
R语言和Python简单对比
找了点关于python和r语言的对比文章看了看,总结了下边几条。
R
统计模型新
可视化,动态报告稍微领先
统计,数据分析,领域专用
Python
效率领先
语言稳定规范
数据清洗方便
工程开发,领域广
我刚开始学习R语言,还没有太多体会,不过从语言层面,感觉R语言的语法分析系统都不完善,不知道为啥函数参数的缺少只能运行时知道,不知道有没有别的作用。
Read more...
Openstack Neutron组件服务(neutron-dhcp-agent服务)
neutron-dhcp-agent服务启动命令
/usr/bin/neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/dhcp_agent.ini
调用了neutron_service.Service.create()来创建的server。Service(n_rpc.Service)继承自neutron_lib.rpc,这次得去看看了,感觉应该也没啥看的。
Service(service.Service)继承自oslo_service.service.Service,里边只是个定义类接口,里边还有个线程池self.tg。
Service传入的manager为neutron.agent.dhcp.agent.DhcpAgentWithStateReport, 然后实例化,最后初始化父类。
DhcpAgentWithStateReport继承自DhcpAgent,再继承自manager.Manager, 然后继承自periodic_task.PeriodicTasks,看起来是个定时任务。先不细看了,按初始化流程走。
在DhcpAgent里dhcp_driver_cls存的dhcp_driver的类,文档安装使用的neutron.agent.linux.dhcp.Dnsmasq,这个先记录,后边看。DhcpPluginApi这个是定义了dhcp rpc的client端,从注释看server端在neutron.api.rpc.handlers.dhcp_rpc.DhcpRpcCallback,具体还不知道为啥这么搞,先记录。看接口内容感觉就是网络的几个常规接口。DhcpAgentWithStateReport里的初始化,也是初始化了一个心跳进行状态上报。
launch方法传入初始化完的server, 启动一个进程,restart方法mutate_config_files on SIGHUP,这个先记录。workers为1走的是ServiceLauncher,继承自Launcher,然后初始化Services,这个也有个线程池。最后初始化SignalHandler。.wait()里边看注释是等待重启服务的信号.
看了一下DhcpRpcCallback,这个看不太懂了,其中的plugin的初始化不太清楚。状态不行,不看这个了。
Dnsmasq继承自DhcpLocalProcess, 再继承自DhcpBase,初始化了一个DeviceManager是与之前的rpc调用相关的没细看。
是通过call_driver来实例化的,但是看起来都是用到的时候才初始化的,看初始化方法和调用,基本都是传入network和action然后,初始化完成后,执行action的方法,所以应该是针对不同网络进行实例化并操作。
主要逻辑都是在Dnsmasq里定义的,existing_dhcp_networks看注释是返回dhcp网络,直接从配置文件目录读取,这个也说明创建网络会在这个目录创建配置文件。_build_cmdline_callback看样子是启动dnsmasq的命令生成的地方。spawn_process启动dnsmasq的进程,调用_get_process_manager,这个是在DhcpLocalProcess, 然后还加入监控。启动是先使用external_process.ProcessManager初始化ProcessManager类,在调用enable()通过传入的cmd_callback,也就是_build_cmdline_callback那个生成cmd,启动服务进程. 随便看了一下,流程连不起来了。这里代码太绕了,不知道怎么个调用的。感觉流程最好搭个环境,打打日志比较好。
这个看的有点失败,获得了很少的东西。
Read more...