【全球新要闻】GO实现Redis:GO实现Redis的AOF持久化(4)
(资料图片仅供参考)
redis.conf
appendonly yesappendfilename appendonly.aof
aof/aof.go
type CmdLine = [][]byteconst ( aofQueueSize = 1 << 16)type payload struct { cmdLine CmdLine dbIndex int}type AofHandler struct { db databaseface.Database aofChan chan *payload aofFile *os.File aofFilename string currentDB int}func NewAOFHandler(db databaseface.Database) (*AofHandler, error) { handler := &AofHandler{} handler.aofFilename = config.Properties.AppendFilename handler.db = db handler.LoadAof() aofFile, err := os.OpenFile(handler.aofFilename, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0600) if err != nil { return nil, err } handler.aofFile = aofFile handler.aofChan = make(chan *payload, aofQueueSize) go func() { handler.handleAof() }() return handler, nil}func (handler *AofHandler) AddAof(dbIndex int, cmdLine CmdLine) { if config.Properties.AppendOnly && handler.aofChan != nil { handler.aofChan <- &payload{ cmdLine: cmdLine, dbIndex: dbIndex, } }}func (handler *AofHandler) handleAof() { handler.currentDB = 0 for p := range handler.aofChan { if p.dbIndex != handler.currentDB { // select db data := reply.MakeMultiBulkReply(utils.ToCmdLine("SELECT", strconv.Itoa(p.dbIndex))).ToBytes() _, err := handler.aofFile.Write(data) if err != nil { logger.Warn(err) continue } handler.currentDB = p.dbIndex } data := reply.MakeMultiBulkReply(p.cmdLine).ToBytes() _, err := handler.aofFile.Write(data) if err != nil { logger.Warn(err) } }}func (handler *AofHandler) LoadAof() { file, err := os.Open(handler.aofFilename) if err != nil { logger.Warn(err) return } defer file.Close() ch := parser.ParseStream(file) fakeConn := &connection.Connection{} for p := range ch { if p.Err != nil { if p.Err == io.EOF { break } logger.Error("parse error: " + p.Err.Error()) continue } if p.Data == nil { logger.Error("empty payload") continue } r, ok := p.Data.(*reply.MultiBulkReply) if !ok { logger.Error("require multi bulk reply") continue } ret := handler.db.Exec(fakeConn, r.Args) if reply.IsErrorReply(ret) { logger.Error("exec err", err) } }}
AofHandler:1.从管道中接收数据 2.写入AOF文件AddAof:用户的指令包装成payload放入管道handleAof:将管道中的payload写入磁盘LoadAof:重启Redis后加载aof文件
database/database.go
type Database struct { dbSet []*DB aofHandler *aof.AofHandler}func NewDatabase() *Database { mdb := &Database{} if config.Properties.Databases == 0 { config.Properties.Databases = 16 } mdb.dbSet = make([]*DB, config.Properties.Databases) for i := range mdb.dbSet { singleDB := makeDB() singleDB.index = i mdb.dbSet[i] = singleDB } if config.Properties.AppendOnly { aofHandler, err := aof.NewAOFHandler(mdb) if err != nil { panic(err) } mdb.aofHandler = aofHandler for _, db := range mdb.dbSet { singleDB := db singleDB.addAof = func(line CmdLine) { mdb.aofHandler.AddAof(singleDB.index, line) } } } return mdb}
将AOF加入到database里使用singleDB的原因:因为在循环中获取返回变量的地址都完全相同,因此当我们想要访问数组中元素所在的地址时,不应该直接获取 range 返回的变量地址 db,而应该使用 singleDB := db
database/db.go
type DB struct { index int data dict.Dict addAof func(CmdLine)}func makeDB() *DB {db := &DB{data: dict.MakeSyncDict(),addAof: func(line CmdLine) {},}return db}
由于分数据库db引用不到aof,所以添加一个addAof匿名函数,在NewDatabase中用这个匿名函数调用AddAof
database/keys.go
func execDel(db *DB, args [][]byte) resp.Reply { ...... if deleted > 0 { db.addAof(utils.ToCmdLine2("del", args...)) } return reply.MakeIntReply(int64(deleted))}func execFlushDB(db *DB, args [][]byte) resp.Reply {db.Flush()db.addAof(utils.ToCmdLine2("flushdb", args...))return &reply.OkReply{}}func execRename(db *DB, args [][]byte) resp.Reply {......db.addAof(utils.ToCmdLine2("rename", args...))return &reply.OkReply{}}func execRenameNx(db *DB, args [][]byte) resp.Reply {......db.addAof(utils.ToCmdLine2("renamenx", args...))return reply.MakeIntReply(1)}
database/string.go
func execSet(db *DB, args [][]byte) resp.Reply { ...... db.addAof(utils.ToCmdLine2("set", args...)) return &reply.OkReply{}}func execSetNX(db *DB, args [][]byte) resp.Reply { ...... db.addAof(utils.ToCmdLine2("setnx", args...)) return reply.MakeIntReply(int64(result))}func execGetSet(db *DB, args [][]byte) resp.Reply { key := string(args[0]) value := args[1] entity, exists := db.GetEntity(key) db.PutEntity(key, &database.DataEntity{Data: value}) db.addAof(utils.ToCmdLine2("getset", args...)) ......}
添加addAof方法
测试命令*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n*2\r\n$6\r\nSELECT\r\n$1\r\n1\r\n
-
【全球新要闻】GO实现Redis:GO实现Redis的AOF持久化(4)将用户发来的指令以RESP协议的形式存储在本地的AOF文件,重启Redis后执行此文件恢复数据https: github com csgopher go-redis本文涉及以下文件:redis
-
【当前热闻】蓄意瞒报两起事故,山西一煤矿34人被问责!蓄意瞒报两起事故,山西一煤矿34人被问责!
-
天天热议:从“一家美”到“家家美”春光明媚,沿着村级公路一路向前,丰富多彩的乡村景观和基础设施,让记者体验了一把“一步一景,景景动人”的乡村“画廊”:一栋
-
碧云泉净水器质量怎么样_碧云 要闻1、碧:浅蓝色碧云,即为浅蓝色的云 如范仲淹名篇《苏幕遮》碧云天,黄花地 秋色连波,波上寒烟翠 山映斜阳天接水,芳草无情,更在斜阳外 黯乡魂,追
-
天气早知道丨阳光来了!不过风有点大…… 世界最资讯已经推移到了华南 今日天气 今天天空状况转好 多云为主,有阳光
-
卸磨杀驴的意思是什么1、卸磨杀驴是指磨完东西后,把拉磨的驴卸下来杀掉。比喻把曾经为自己出过力的人一脚踢开。2、卸磨杀驴拼音:xièmòshālǘ3、出处:刘绍棠《
-
高中数学成绩不下140分,无非刷透这529道必考题,高一高二均适用-天天资讯很多高一高二的家长错误地以为高一高二对孩子可以松懈点,到了高三把落下的知识点补上来就可以了,熟不知孩子学得内容越落越多,最后不得不放
-
厚积薄发李少庚黄竹风吴可欣离特大一步之遥,小将孟繁睿等待绽放本次赛事前六诞生后值得期待的三位强大师,能否成为特大,将吸引无数人的目光。黄竹风屹立不倒,让人看到了“铁布衫”的影子,他的棋风刚硬...
-
讯息:拼多多查看收件人信息怎么申诉_拼多多查看收件人信息1、不是。2、是规则改了。3、我这边还有其他同行进行交流的时候都是这样的。本文就为大家分享到这里,希望小伙伴们会喜欢。
-
男与女电影2016剧情-天天时讯1、在下着鹅毛大雪的芬兰,一对男女在异地相遇。在芬兰国际学校里偶遇的尚敏(全度妍饰)和基洪(孔刘饰)被安排一同前往北校区,由于暴雪导致
-
热门看点:北京沙尘大风预警齐发 广大市民注意防范沙尘暴天气今天来回顾关于北京沙尘大风预警齐发广大市民注意防范沙尘暴天气的文章,希望对各位小伙伴们有所帮助。【北京沙尘大风预警齐发
-
一方混凝c25多少钱_一方c25混凝土价格 热点聚焦1、各地方价格有差异,主要是地材(砂子、碎石)价格不同以及运距差。2、C25商品砼平均水平大约310元 立方。本文到此
-
新资讯:全球黄金储备量前20名,各国央行“买买买”,民间藏金量引发热议全球黄金储备量前20名,各国央行“买买买”,民间藏金量引发热议,藏金量,黄金储备量
-
孤城闭帝后结局 环球关注1、《孤城闭》历史上曹皇后是病逝的,终年六十四岁,比宋仁宗活的时间要长一些,她的宽容大度是出了名的。2、曹皇后出身于名门,祖父曹彬是开
-
2023河南南阳市直机关遴选公务员面试确认公告_当前看点按照《南阳市2023年市直机关公开遴选公务员公告》规定要求,根据拟录用职位与参加面试人数1:3的比例,按照笔试成绩从到低
-
【时快讯】上海三大未来产业先导区(张江、临港、大零号湾)授牌上海三大未来产业先导区(张江、临港、大零号湾)授牌
-
深交所牵头的国家重点研发计划“证券市场异常交易行为智能监测发现技术及应用示范”项目正式启动实施_环球新资讯App3月25日消息,深圳证券交易所3月22日在北京成功举办国家重点研发计划“社会治理与智慧社会科技支撑”重点专项——“证券市场异常行为智...
-
如何学习算牌计牌_当前观察1、日常生活中和朋友打牌有意识的训练即可,比如斗地主:一开始你需要先记住一对王,四个2,有人出过这些牌你就得记住,后面可以记着4个A,还
-
【环球新视野】客户服务培训(员工培训可以改善客户服务的重点嘛)本文目录一览:1、客户服务与沟通技巧2、客户服务人员培训要遵循哪些原则3、为什么要进行客户服务培训4
-
环球观察:50kb是多大像素_50kb是多少像素1、推荐“光影魔术手”做此处理比其他软件方便些。2、如果原来的照片长边略比517大一点,可以直接进入“裁剪”-“固定边长
-
当前观点:英国电池创企Britishvolt寻求出售多数股权,为超级工厂计划筹集资金英国《金融时报》1月9日消息,英国电池初创企业Britishvolt表示,该公司正谈判将大部分股权出售给一个投资者财团,
-
湖北郧阳:韭菜花开致富路湖北郧阳:韭菜花开致富路
-
基围虾做法大全家常菜_基围虾做法大全家常 全球短讯1、红烧基围虾。2、原料:基围虾300克、姜少许、小葱少许。3、调料:酱油(老抽)、糖、盐。4、做法:虾洗净,剪去长须沥
-
【世界独家】学做面包制作配方1、准备食材。用配方里一般的温水溶解酵母粉。2、把称好的面粉等干性的食材倒在一起,搅拌均匀。3、混合好后,倒入已经溶解好的酵母。加入剩下
-
欧股持续走低 欧洲斯托克50指数跌逾2%【行情】欧股持续走低,欧洲斯托克50指数跌逾2%,德国DAX指数、法国CAC40指数跌近2%。银行股表现不佳,欧股德意志银行跌10%。
-
滚动:老头乐车企栽了!山东小彭向广州小鹏汽车致歉 停售侵权车型老头乐车企栽了!山东小彭向广州小鹏汽车致歉停售侵权车型
-
【世界新要闻】淘宝店铺卖什么类目比较好?有哪些可以选?在淘宝这个平台上,大家开店一般都是会去售卖商品的,在淘宝上买商品的时候,首先需要选择好相关的类目才行,类目选好一般都不会更改了,淘
-
英村脑残故事_关于英村脑残故事的简介 全球短讯1、《英村脑残故事》是由TomGeorge执导,DaisyMayCooper、CharlieCooper主演
-
塞尔达传说新手攻略的顺序_新手刚刚接触轨迹系列 应该按照什么顺序玩|时快讯1、空之轨迹分为FCSC3RD,然后版本的话都有PC和PSP,没有PSV。2、先FC,然后SC,最后3RD。3、之后
-
环球热消息:李菁菁主演的电视剧大全_李菁菁的丈夫是谁1、【李菁菁个人资料】李菁菁出生于内蒙一个普通工人家庭。2、她的父母是北京知青,在她3岁时随父母一起来到了山西大同。3、