mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 08:46:56 +08:00
direct call for FsyncAlways
This commit is contained in:
98
aof/aof.go
98
aof/aof.go
@@ -61,6 +61,8 @@ type Persister struct {
|
|||||||
pausingAof sync.Mutex
|
pausingAof sync.Mutex
|
||||||
currentDB int
|
currentDB int
|
||||||
listeners map[Listener]struct{}
|
listeners map[Listener]struct{}
|
||||||
|
// reuse cmdLine buffer
|
||||||
|
buffer []CmdLine
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPersister creates a new aof.Persister
|
// NewPersister creates a new aof.Persister
|
||||||
@@ -70,6 +72,7 @@ func NewPersister(db database.DBEngine, filename string, load bool, fsync string
|
|||||||
persister.aofFsync = strings.ToLower(fsync)
|
persister.aofFsync = strings.ToLower(fsync)
|
||||||
persister.db = db
|
persister.db = db
|
||||||
persister.tmpDBMaker = tmpDBMaker
|
persister.tmpDBMaker = tmpDBMaker
|
||||||
|
persister.currentDB = 0
|
||||||
if load {
|
if load {
|
||||||
persister.LoadAof(0)
|
persister.LoadAof(0)
|
||||||
}
|
}
|
||||||
@@ -100,20 +103,6 @@ func (persister *Persister) RemoveListener(listener Listener) {
|
|||||||
delete(persister.listeners, listener)
|
delete(persister.listeners, listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
var wgPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return &sync.WaitGroup{}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func getWg() *sync.WaitGroup {
|
|
||||||
return wgPool.Get().(*sync.WaitGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
func returnWg(wg *sync.WaitGroup) {
|
|
||||||
wgPool.Put(wg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveCmdLine send command to aof goroutine through channel
|
// SaveCmdLine send command to aof goroutine through channel
|
||||||
func (persister *Persister) SaveCmdLine(dbIndex int, cmdLine CmdLine) {
|
func (persister *Persister) SaveCmdLine(dbIndex int, cmdLine CmdLine) {
|
||||||
// aofChan will be set as nil temporarily during load aof see Persister.LoadAof
|
// aofChan will be set as nil temporarily during load aof see Persister.LoadAof
|
||||||
@@ -121,16 +110,12 @@ func (persister *Persister) SaveCmdLine(dbIndex int, cmdLine CmdLine) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if persister.aofFsync == FsyncAlways {
|
if persister.aofFsync == FsyncAlways {
|
||||||
// use WaitGroup to wait for saving finished
|
p := &payload{
|
||||||
wg := getWg()
|
|
||||||
defer returnWg(wg)
|
|
||||||
wg.Add(1)
|
|
||||||
persister.aofChan <- &payload{
|
|
||||||
cmdLine: cmdLine,
|
cmdLine: cmdLine,
|
||||||
dbIndex: dbIndex,
|
dbIndex: dbIndex,
|
||||||
wg: wg,
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
persister.writeAof(p)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
persister.aofChan <- &payload{
|
persister.aofChan <- &payload{
|
||||||
cmdLine: cmdLine,
|
cmdLine: cmdLine,
|
||||||
@@ -140,46 +125,42 @@ func (persister *Persister) SaveCmdLine(dbIndex int, cmdLine CmdLine) {
|
|||||||
|
|
||||||
// listenCmd listen aof channel and write into file
|
// listenCmd listen aof channel and write into file
|
||||||
func (persister *Persister) listenCmd() {
|
func (persister *Persister) listenCmd() {
|
||||||
// serialized execution
|
|
||||||
var cmdLines []CmdLine
|
|
||||||
persister.currentDB = 0
|
|
||||||
for p := range persister.aofChan {
|
for p := range persister.aofChan {
|
||||||
cmdLines = cmdLines[:0] // reuse underlying array
|
persister.writeAof(p)
|
||||||
persister.pausingAof.Lock() // prevent other goroutines from pausing aof
|
}
|
||||||
// ensure aof is in the right database
|
persister.aofFinished <- struct{}{}
|
||||||
if p.dbIndex != persister.currentDB {
|
}
|
||||||
// select db
|
|
||||||
selectCmd := utils.ToCmdLine("SELECT", strconv.Itoa(p.dbIndex))
|
func (persister *Persister) writeAof(p *payload) {
|
||||||
cmdLines = append(cmdLines, selectCmd)
|
persister.buffer = persister.buffer[:0] // reuse underlying array
|
||||||
data := protocol.MakeMultiBulkReply(selectCmd).ToBytes()
|
persister.pausingAof.Lock() // prevent other goroutines from pausing aof
|
||||||
_, err := persister.aofFile.Write(data)
|
defer persister.pausingAof.Unlock()
|
||||||
if err != nil {
|
// ensure aof is in the right database
|
||||||
logger.Warn(err)
|
if p.dbIndex != persister.currentDB {
|
||||||
persister.pausingAof.Unlock()
|
// select db
|
||||||
continue // skip this command
|
selectCmd := utils.ToCmdLine("SELECT", strconv.Itoa(p.dbIndex))
|
||||||
}
|
persister.buffer = append(persister.buffer, selectCmd)
|
||||||
persister.currentDB = p.dbIndex
|
data := protocol.MakeMultiBulkReply(selectCmd).ToBytes()
|
||||||
}
|
|
||||||
// save command
|
|
||||||
data := protocol.MakeMultiBulkReply(p.cmdLine).ToBytes()
|
|
||||||
cmdLines = append(cmdLines, p.cmdLine)
|
|
||||||
_, err := persister.aofFile.Write(data)
|
_, err := persister.aofFile.Write(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn(err)
|
logger.Warn(err)
|
||||||
|
return // skip this command
|
||||||
}
|
}
|
||||||
for listener := range persister.listeners {
|
persister.currentDB = p.dbIndex
|
||||||
listener.Callback(cmdLines)
|
}
|
||||||
}
|
// save command
|
||||||
if persister.aofFsync == FsyncAlways {
|
data := protocol.MakeMultiBulkReply(p.cmdLine).ToBytes()
|
||||||
_ = persister.aofFile.Sync()
|
persister.buffer = append(persister.buffer, p.cmdLine)
|
||||||
}
|
_, err := persister.aofFile.Write(data)
|
||||||
if p.wg != nil {
|
if err != nil {
|
||||||
p.wg.Done()
|
logger.Warn(err)
|
||||||
}
|
}
|
||||||
persister.pausingAof.Unlock()
|
for listener := range persister.listeners {
|
||||||
|
listener.Callback(persister.buffer)
|
||||||
|
}
|
||||||
|
if persister.aofFsync == FsyncAlways {
|
||||||
|
_ = persister.aofFile.Sync()
|
||||||
}
|
}
|
||||||
persister.aofFinished <- struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAof read aof file, can only be used before Persister.listenCmd started
|
// LoadAof read aof file, can only be used before Persister.listenCmd started
|
||||||
@@ -231,6 +212,13 @@ func (persister *Persister) LoadAof(maxBytes int) {
|
|||||||
if protocol.IsErrorReply(ret) {
|
if protocol.IsErrorReply(ret) {
|
||||||
logger.Error("exec err", string(ret.ToBytes()))
|
logger.Error("exec err", string(ret.ToBytes()))
|
||||||
}
|
}
|
||||||
|
if strings.ToLower(string(r.Args[0])) == "select" {
|
||||||
|
// execSelect success, here must be no error
|
||||||
|
dbIndex, err := strconv.Atoi(string(r.Args[1]))
|
||||||
|
if err == nil {
|
||||||
|
persister.currentDB = dbIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,7 +53,8 @@ func TestServerFsyncAlways(t *testing.T) {
|
|||||||
config.Properties.AppendFsync = aof.FsyncAlways
|
config.Properties.AppendFsync = aof.FsyncAlways
|
||||||
server := NewStandaloneServer()
|
server := NewStandaloneServer()
|
||||||
conn := connection.NewFakeConn()
|
conn := connection.NewFakeConn()
|
||||||
ret := server.Exec(conn, utils.ToCmdLine("set", "1", "1"))
|
server.Exec(conn, utils.ToCmdLine("del", "1"))
|
||||||
|
ret := server.Exec(conn, utils.ToCmdLine("incr", "1"))
|
||||||
asserts.AssertNotError(t, ret)
|
asserts.AssertNotError(t, ret)
|
||||||
reader := NewStandaloneServer()
|
reader := NewStandaloneServer()
|
||||||
ret = reader.Exec(conn, utils.ToCmdLine("get", "1"))
|
ret = reader.Exec(conn, utils.ToCmdLine("get", "1"))
|
||||||
@@ -71,7 +72,8 @@ func TestServerFsyncEverySec(t *testing.T) {
|
|||||||
config.Properties.AppendFsync = aof.FsyncEverySec
|
config.Properties.AppendFsync = aof.FsyncEverySec
|
||||||
server := NewStandaloneServer()
|
server := NewStandaloneServer()
|
||||||
conn := connection.NewFakeConn()
|
conn := connection.NewFakeConn()
|
||||||
ret := server.Exec(conn, utils.ToCmdLine("set", "1", "1"))
|
server.Exec(conn, utils.ToCmdLine("del", "1"))
|
||||||
|
ret := server.Exec(conn, utils.ToCmdLine("incr", "1"))
|
||||||
asserts.AssertNotError(t, ret)
|
asserts.AssertNotError(t, ret)
|
||||||
time.Sleep(1500 * time.Millisecond)
|
time.Sleep(1500 * time.Millisecond)
|
||||||
reader := NewStandaloneServer()
|
reader := NewStandaloneServer()
|
||||||
|
Reference in New Issue
Block a user