func (l *BinLog) flushIndex() error { data := strings.Join(l.logNames, "\n") bakName := fmt.Sprintf("%s.bak", l.indexName) f, err := os.OpenFile(bakName, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { log.Error("create binlog bak index error %s", err.Error()) return err } if _, err := f.WriteString(data); err != nil { log.Error("write binlog index error %s", err.Error()) f.Close() return err } f.Close() if err := os.Rename(bakName, l.indexName); err != nil { log.Error("rename binlog bak index error %s", err.Error()) return err } return nil }
func (l *BinLog) loadIndex() error { l.indexName = path.Join(l.cfg.Path, fmt.Sprintf("ledis-bin.index")) if _, err := os.Stat(l.indexName); os.IsNotExist(err) { //no index file, nothing to do } else { indexData, err := ioutil.ReadFile(l.indexName) if err != nil { return err } lines := strings.Split(string(indexData), "\n") for _, line := range lines { line = strings.Trim(line, "\r\n ") if len(line) == 0 { continue } if _, err := os.Stat(path.Join(l.cfg.Path, line)); err != nil { log.Error("load index line %s error %s", line, err.Error()) return err } else { l.logNames = append(l.logNames, line) } } } if l.cfg.MaxFileNum > 0 && len(l.logNames) > l.cfg.MaxFileNum { //remove oldest logfile if err := l.Purge(len(l.logNames) - l.cfg.MaxFileNum); err != nil { return err } } var err error if len(l.logNames) == 0 { l.lastLogIndex = 1 } else { lastName := l.logNames[len(l.logNames)-1] if l.lastLogIndex, err = strconv.ParseInt(path.Ext(lastName)[1:], 10, 64); err != nil { log.Error("invalid logfile name %s", err.Error()) return err } //like mysql, if server restart, a new binlog will create l.lastLogIndex++ } return nil }
func (l *BinLog) openNewLogFile() error { var err error lastName := l.getLogFile() logPath := path.Join(l.cfg.Path, lastName) if l.logFile, err = os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY, 0666); err != nil { log.Error("open new logfile error %s", err.Error()) return err } if l.cfg.MaxFileNum > 0 && len(l.logNames) == l.cfg.MaxFileNum { l.purge(1) } l.logNames = append(l.logNames, lastName) if l.logWb == nil { l.logWb = bufio.NewWriterSize(l.logFile, 1024) } else { l.logWb.Reset(l.logFile) } if err = l.flushIndex(); err != nil { return err } return nil }
func (l *Ledis) FlushAll() error { for index, db := range l.dbs { if _, err := db.FlushAll(); err != nil { log.Error("flush db %d error %s", index, err.Error()) } } return nil }
func (m *master) runReplication() { m.wg.Add(1) defer m.wg.Done() for { select { case <-m.quit: return default: if err := m.connect(); err != nil { log.Error("connect master %s error %s, try 2s later", m.addr, err.Error()) time.Sleep(2 * time.Second) continue } } if m.logFileIndex == 0 { //try a fullsync if err := m.fullSync(); err != nil { log.Warn("full sync error %s", err.Error()) return } if m.logFileIndex == 0 { //master not support binlog, we cannot sync, so stop replication m.stopReplication() return } } for { for { lastIndex := m.logFileIndex lastPos := m.logPos if err := m.sync(); err != nil { log.Warn("sync error %s", err.Error()) return } if m.logFileIndex == lastIndex && m.logPos == lastPos { //sync no data, wait 1s and retry break } } select { case <-m.quit: return case <-time.After(1 * time.Second): break } } } return }
func (m *master) stopReplication() error { m.Close() if err := m.saveInfo(); err != nil { log.Error("save master info error %s", err.Error()) return err } return nil }
func (m *master) fullSync() error { if _, err := m.c.Write(fullSyncCmd); err != nil { return err } dumpPath := path.Join(m.app.cfg.DataDir, "master.dump") f, err := os.OpenFile(dumpPath, os.O_CREATE|os.O_WRONLY, os.ModePerm) if err != nil { return err } defer os.Remove(dumpPath) err = readBulkTo(m.rb, f) f.Close() if err != nil { log.Error("read dump data error %s", err.Error()) return err } if err = m.app.ldb.FlushAll(); err != nil { return err } var head *ledis.MasterInfo head, err = m.app.ldb.LoadDumpFile(dumpPath) if err != nil { log.Error("load dump file error %s", err.Error()) return err } m.logFileIndex = head.LogFileIndex m.logPos = head.LogPos return m.saveInfo() }
func (m *master) startReplication(masterAddr string) error { //stop last replcation, if avaliable m.Close() if masterAddr != m.addr { m.resetInfo(masterAddr) if err := m.saveInfo(); err != nil { log.Error("save master info error %s", err.Error()) return err } } m.quit = make(chan struct{}, 1) go m.runReplication() return nil }
func (l *BinLog) Log(args ...[]byte) error { var err error if l.logFile == nil { if err = l.openNewLogFile(); err != nil { return err } } //we treat log many args as a batch, so use same createTime createTime := uint32(time.Now().Unix()) for _, data := range args { payLoadLen := uint32(len(data)) if err := binary.Write(l.logWb, binary.BigEndian, createTime); err != nil { return err } if err := binary.Write(l.logWb, binary.BigEndian, payLoadLen); err != nil { return err } if _, err := l.logWb.Write(data); err != nil { return err } } if err = l.logWb.Flush(); err != nil { log.Error("write log error %s", err.Error()) return err } l.checkLogFileSize() return nil }