GO realizes AOF persistence of Redis
Store the instructions sent by the user in the local AOF file in the form of RESP protocol. After restarting Redis, perform this file to restore data.
/csgopher/go-redis
This article involves the following files:: Configuration files
aof: implement aof
appendonly yes
appendfilename
aof/
type CmdLine = [][]byte const ( aofQueueSize = 1 << 16 ) type payload struct { cmdLine CmdLine dbIndex int } type AofHandler struct { db aofChan chan *payload aofFile * aofFilename string currentDB int } func NewAOFHandler(db ) (*AofHandler, error) { handler := &AofHandler{} = = db () aofFile, err := (, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0600) if err != nil { return nil, err } = aofFile = make(chan *payload, aofQueueSize) go func() { () }() return handler, nil } func (handler *AofHandler) AddAof(dbIndex int, cmdLine CmdLine) { if && != nil { <- &payload{ cmdLine: cmdLine, dbIndex: dbIndex, } } } func (handler *AofHandler) handleAof() { = 0 for p := range { if != { // select db data := (("SELECT", ())).ToBytes() _, err := (data) if err != nil { (err) continue } = } data := ().ToBytes() _, err := (data) if err != nil { (err) } } } func (handler *AofHandler) LoadAof() { file, err := () if err != nil { (err) return } defer () ch := (file) fakeConn := &{} for p := range ch { if != nil { if == { break } ("parse error: " + ()) continue } if == nil { ("empty payload") continue } r, ok := .(*) if !ok { ("require multi bulk reply") continue } ret := (fakeConn, ) if (ret) { ("exec err", err) } } }
- AofHandler: 1. Receive data from the pipeline 2. Write to the AOF file
- AddAof: User's instructions are packaged into payload and put into the pipeline
- handleAof: Write payload in the pipeline to disk
- LoadAof: Load aof file after restarting Redis
database/
type Database struct { dbSet []*DB aofHandler * } func NewDatabase() *Database { mdb := &Database{} if == 0 { = 16 } = make([]*DB, ) for i := range { singleDB := makeDB() = i [i] = singleDB } if { aofHandler, err := (mdb) if err != nil { panic(err) } = aofHandler for _, db := range { singleDB := db = func(line CmdLine) { (, line) } } } return mdb }
Add AOF to database
Reasons to use singleDB: Because the address of the return variable in the loop is exactly the same, when we want to access the address where the element in the array is, we should not directly obtain the variable address db returned by range, but should use singleDB := db
database/
type DB struct { index int data addAof func(CmdLine) } func makeDB() *DB { db := &DB{ data: (), addAof: func(line CmdLine) {}, } return db }
Since the database db cannot reference aof, add an anonymous function of addAof and use this anonymous function to call AddAof in NewDatabase
database/
func execDel(db *DB, args [][]byte) { ...... if deleted > 0 { (utils.ToCmdLine2("del", args...)) } return (int64(deleted)) } func execFlushDB(db *DB, args [][]byte) { () (utils.ToCmdLine2("flushdb", args...)) return &{} } func execRename(db *DB, args [][]byte) { ...... (utils.ToCmdLine2("rename", args...)) return &{} } func execRenameNx(db *DB, args [][]byte) { ...... (utils.ToCmdLine2("renamenx", args...)) return (1) }
database/
func execSet(db *DB, args [][]byte) { ...... (utils.ToCmdLine2("set", args...)) return &{} } func execSetNX(db *DB, args [][]byte) { ...... (utils.ToCmdLine2("setnx", args...)) return (int64(result)) } func execGetSet(db *DB, args [][]byte) { key := string(args[0]) value := args[1] entity, exists := (key) (key, &{Data: value}) (utils.ToCmdLine2("getset", args...)) ...... }
Add addAof method
Test command
*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
This is the end of this article about how GO realizes AOF persistence of Redis. For more related GO to realize Redis AOF persistence, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!