add MasterInfo for replication

This commit is contained in:
siddontang 2014-07-11 16:57:19 +08:00
parent 31320944e6
commit ac5c64aab8
1 changed files with 73 additions and 67 deletions

View File

@ -23,13 +23,55 @@ var (
errConnectMaster = errors.New("connect master error") errConnectMaster = errors.New("connect master error")
) )
type MasterInfo struct {
Addr string `json:"addr"`
LogFileIndex int64 `json:"log_file_index"`
LogPos int64 `json:"log_pos"`
}
func (m *MasterInfo) Save(filePath string) error {
data, err := json.Marshal(m)
if err != nil {
return err
}
filePathBak := fmt.Sprintf("%s.bak", filePath)
var fd *os.File
fd, err = os.OpenFile(filePathBak, os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
return err
}
if _, err = fd.Write(data); err != nil {
fd.Close()
return err
}
fd.Close()
return os.Rename(filePathBak, filePath)
}
func (m *MasterInfo) Load(filePath string) error {
data, err := ioutil.ReadFile(filePath)
if err != nil {
if os.IsNotExist(err) {
return nil
} else {
return err
}
}
if err = json.Unmarshal(data, m); err != nil {
return err
}
return nil
}
type master struct { type master struct {
sync.Mutex sync.Mutex
addr string `json:"addr"`
logFileIndex int64 `json:"log_file_index"`
logPos int64 `json:"log_pos"`
c net.Conn c net.Conn
rb *bufio.Reader rb *bufio.Reader
@ -38,7 +80,8 @@ type master struct {
quit chan struct{} quit chan struct{}
infoName string infoName string
infoNameBak string
info *MasterInfo
wg sync.WaitGroup wg sync.WaitGroup
@ -52,12 +95,13 @@ func newMaster(app *App) *master {
m.app = app m.app = app
m.infoName = path.Join(m.app.cfg.DataDir, "master.info") m.infoName = path.Join(m.app.cfg.DataDir, "master.info")
m.infoNameBak = fmt.Sprintf("%s.bak", m.infoName)
m.quit = make(chan struct{}, 1) m.quit = make(chan struct{}, 1)
m.compressBuf = make([]byte, 256) m.compressBuf = make([]byte, 256)
m.info = new(MasterInfo)
//if load error, we will start a fullsync later //if load error, we will start a fullsync later
m.loadInfo() m.loadInfo()
@ -79,53 +123,15 @@ func (m *master) Close() {
} }
func (m *master) loadInfo() error { func (m *master) loadInfo() error {
data, err := ioutil.ReadFile(m.infoName) return m.info.Load(m.infoName)
if err != nil {
if os.IsNotExist(err) {
return nil
} else {
return err
}
}
if err = json.Unmarshal(data, m); err != nil {
return err
}
return nil
} }
func (m *master) saveInfo() error { func (m *master) saveInfo() error {
data, err := json.Marshal(struct { return m.info.Save(m.infoName)
Addr string `json:"addr"`
LogFileIndex int64 `json:"log_file_index"`
LogPos int64 `json:"log_pos"`
}{
m.addr,
m.logFileIndex,
m.logPos,
})
if err != nil {
return err
}
var fd *os.File
fd, err = os.OpenFile(m.infoNameBak, os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
return err
}
if _, err = fd.Write(data); err != nil {
fd.Close()
return err
}
fd.Close()
return os.Rename(m.infoNameBak, m.infoName)
} }
func (m *master) connect() error { func (m *master) connect() error {
if len(m.addr) == 0 { if len(m.info.Addr) == 0 {
return fmt.Errorf("no assign master addr") return fmt.Errorf("no assign master addr")
} }
@ -134,7 +140,7 @@ func (m *master) connect() error {
m.c = nil m.c = nil
} }
if c, err := net.Dial("tcp", m.addr); err != nil { if c, err := net.Dial("tcp", m.info.Addr); err != nil {
return err return err
} else { } else {
m.c = c m.c = c
@ -145,9 +151,9 @@ func (m *master) connect() error {
} }
func (m *master) resetInfo(addr string) { func (m *master) resetInfo(addr string) {
m.addr = addr m.info.Addr = addr
m.logFileIndex = 0 m.info.LogFileIndex = 0
m.logPos = 0 m.info.LogPos = 0
} }
func (m *master) stopReplication() error { func (m *master) stopReplication() error {
@ -165,7 +171,7 @@ func (m *master) startReplication(masterAddr string) error {
//stop last replcation, if avaliable //stop last replcation, if avaliable
m.Close() m.Close()
if masterAddr != m.addr { if masterAddr != m.info.Addr {
m.resetInfo(masterAddr) m.resetInfo(masterAddr)
if err := m.saveInfo(); err != nil { if err := m.saveInfo(); err != nil {
log.Error("save master info error %s", err.Error()) log.Error("save master info error %s", err.Error())
@ -189,20 +195,20 @@ func (m *master) runReplication() {
return return
default: default:
if err := m.connect(); err != nil { if err := m.connect(); err != nil {
log.Error("connect master %s error %s, try 2s later", m.addr, err.Error()) log.Error("connect master %s error %s, try 2s later", m.info.Addr, err.Error())
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
continue continue
} }
} }
if m.logFileIndex == 0 { if m.info.LogFileIndex == 0 {
//try a fullsync //try a fullsync
if err := m.fullSync(); err != nil { if err := m.fullSync(); err != nil {
log.Warn("full sync error %s", err.Error()) log.Warn("full sync error %s", err.Error())
return return
} }
if m.logFileIndex == 0 { if m.info.LogFileIndex == 0 {
//master not support binlog, we cannot sync, so stop replication //master not support binlog, we cannot sync, so stop replication
m.stopReplication() m.stopReplication()
return return
@ -211,14 +217,14 @@ func (m *master) runReplication() {
for { for {
for { for {
lastIndex := m.logFileIndex lastIndex := m.info.LogFileIndex
lastPos := m.logPos lastPos := m.info.LogPos
if err := m.sync(); err != nil { if err := m.sync(); err != nil {
log.Warn("sync error %s", err.Error()) log.Warn("sync error %s", err.Error())
return return
} }
if m.logFileIndex == lastIndex && m.logPos == lastPos { if m.info.LogFileIndex == lastIndex && m.info.LogPos == lastPos {
//sync no data, wait 1s and retry //sync no data, wait 1s and retry
break break
} }
@ -273,15 +279,15 @@ func (m *master) fullSync() error {
return err return err
} }
m.logFileIndex = head.LogFileIndex m.info.LogFileIndex = head.LogFileIndex
m.logPos = head.LogPos m.info.LogPos = head.LogPos
return m.saveInfo() return m.saveInfo()
} }
func (m *master) sync() error { func (m *master) sync() error {
logIndexStr := strconv.FormatInt(m.logFileIndex, 10) logIndexStr := strconv.FormatInt(m.info.LogFileIndex, 10)
logPosStr := strconv.FormatInt(m.logPos, 10) logPosStr := strconv.FormatInt(m.info.LogPos, 10)
cmd := ledis.Slice(fmt.Sprintf(syncCmdFormat, len(logIndexStr), cmd := ledis.Slice(fmt.Sprintf(syncCmdFormat, len(logIndexStr),
logIndexStr, len(logPosStr), logPosStr)) logIndexStr, len(logPosStr), logPosStr))
@ -308,14 +314,14 @@ func (m *master) sync() error {
return fmt.Errorf("invalid sync data len %d", len(buf)) return fmt.Errorf("invalid sync data len %d", len(buf))
} }
m.logFileIndex = int64(binary.BigEndian.Uint64(buf[0:8])) m.info.LogFileIndex = int64(binary.BigEndian.Uint64(buf[0:8]))
m.logPos = int64(binary.BigEndian.Uint64(buf[8:16])) m.info.LogPos = int64(binary.BigEndian.Uint64(buf[8:16]))
if m.logFileIndex == 0 { if m.info.LogFileIndex == 0 {
//master now not support binlog, stop replication //master now not support binlog, stop replication
m.stopReplication() m.stopReplication()
return nil return nil
} else if m.logFileIndex == -1 { } else if m.info.LogFileIndex == -1 {
//-1 means than binlog index and pos are lost, we must start a full sync instead //-1 means than binlog index and pos are lost, we must start a full sync instead
return m.fullSync() return m.fullSync()
} }