func (c *Conn) Run() { defer func() { r := recover() if err, ok := r.(error); ok { const size = 4096 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Error("%v, %s", err, buf) } c.Close() }() for { data, err := c.readPacket() if err != nil { return } if err := c.dispatch(data); err != nil { log.Error("dispatch error %s", err.Error()) if err != ErrBadConn { c.writeError(err) } } c.pkg.Sequence = 0 } }
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.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.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 writeBSON(result interface{}, w http.ResponseWriter) { buf, err := bson.Marshal(result) if err != nil { log.Error(err.Error()) return } w.Header().Set("Content-type", "application/octet-stream") w.Header().Set("Content-Length", strconv.Itoa(len(buf))) _, err = w.Write(buf) if err != nil { log.Error(err.Error()) } }
func writeJSON(resutl interface{}, w http.ResponseWriter) { buf, err := json.Marshal(resutl) if err != nil { log.Error(err.Error()) return } w.Header().Set("Content-type", "application/json; charset=utf-8") w.Header().Set("Content-Length", strconv.Itoa(len(buf))) _, err = w.Write(buf) if err != nil { log.Error(err.Error()) } }
func (l *BinLog) openNewLogFile() error { var err error lastName := l.getLogFile() logPath := path.Join(l.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 (s *Server) parseNode(cfg config.NodeConfig) (*Node, error) { n := new(Node) n.server = s n.cfg = cfg n.downAfterNoAlive = time.Duration(cfg.DownAfterNoAlive) * time.Second if len(cfg.Master) == 0 { return nil, fmt.Errorf("must setting master MySQL node.") } var err error if n.master, err = n.openDB(cfg.Master); err != nil { return nil, err } n.db = n.master if len(cfg.Slave) > 0 { if n.slave, err = n.openDB(cfg.Slave); err != nil { log.Error(err.Error()) n.slave = nil } } go n.run() return n, 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 writeMsgPack(result interface{}, w http.ResponseWriter) { w.Header().Set("Content-type", "application/octet-stream") var mh codec.MsgpackHandle enc := codec.NewEncoder(w, &mh) if err := enc.Encode(result); err != nil { log.Error(err.Error()) } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) flag.Parse() if len(*configFile) == 0 { log.Error("must use a config file") return } cfg, err := config.ParseConfigFile(*configFile) if err != nil { log.Error(err.Error()) return } if *logLevel != "" { setLogLevel(*logLevel) } else { setLogLevel(cfg.LogLevel) } var svr *proxy.Server svr, err = proxy.NewServer(cfg) if err != nil { log.Error(err.Error()) return } sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) go func() { sig := <-sc log.Info("Got signal [%d] to exit.", sig) svr.Close() }() svr.Run() }
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.info.Addr, err.Error()) time.Sleep(2 * time.Second) continue } } if m.info.LogFileIndex == 0 { //try a fullsync if err := m.fullSync(); err != nil { log.Warn("full sync error %s", err.Error()) return } if m.info.LogFileIndex == 0 { //master not support binlog, we cannot sync, so stop replication m.stopReplication() return } } for { for { lastIndex := m.info.LogFileIndex lastPos := m.info.LogPos if err := m.sync(); err != nil { log.Warn("sync error %s", err.Error()) return } if m.info.LogFileIndex == lastIndex && m.info.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 (n *Node) checkSlave() { if n.slave == nil { return } db := n.slave if err := db.Ping(); err != nil { log.Error("%s ping slave %s error %s", n, db.Addr(), err.Error()) } else { n.lastSlavePing = time.Now().Unix() } if int64(n.downAfterNoAlive) > 0 && time.Now().Unix()-n.lastSlavePing > int64(n.downAfterNoAlive) { log.Error("%s slave db %s not alive over %ds, down it", n, db.Addr(), int64(n.downAfterNoAlive/time.Second)) n.downSlave() } }
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.info.Addr, err.Error()) time.Sleep(2 * time.Second) continue } } if m.info.LogFileIndex == 0 { //try a fullsync if err := m.fullSync(); err != nil { if m.conn != nil { //if conn == nil, other close the replication, not error log.Warn("full sync error %s", err.Error()) } return } if m.info.LogFileIndex == 0 { //master not support binlog, we cannot sync, so stop replication m.stopReplication() return } } for { if err := m.sync(); err != nil { if m.conn != nil { //if conn == nil, other close the replication, not error log.Warn("sync error %s", err.Error()) } return } select { case <-m.quit: return default: break } } } return }
func (n *Node) checkMaster() { n.Lock() db := n.db n.Unlock() if db == nil { log.Info("no master avaliable") return } if err := db.Ping(); err != nil { log.Error("%s ping master %s error %s", n, db.Addr(), err.Error()) } else { n.lastMasterPing = time.Now().Unix() return } if int64(n.downAfterNoAlive) > 0 && time.Now().Unix()-n.lastMasterPing > int64(n.downAfterNoAlive) { log.Error("%s down master db %s", n, n.master.Addr()) n.downMater() } }
func (s *Server) onConn(c net.Conn) { conn := s.newConn(c) defer func() { if err := recover(); err != nil { const size = 4096 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Error("onConn panic %v: %v\n%s", c.RemoteAddr().String(), err, buf) } conn.Close() }() if err := conn.Handshake(); err != nil { log.Error("handshake error %s", err.Error()) c.Close() return } conn.Run() }
func (c *Conn) Handshake() error { if err := c.writeInitialHandshake(); err != nil { log.Error("send initial handshake error %s", err.Error()) return err } if err := c.readHandshakeResponse(); err != nil { log.Error("recv handshake response error %s", err.Error()) c.writeError(err) return err } if err := c.writeOK(nil); err != nil { log.Error("write ok fail %s", err.Error()) return err } c.pkg.Sequence = 0 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.info.LogFileIndex = head.LogFileIndex m.info.LogPos = head.LogPos return m.saveInfo() }
func (s *Server) Run() error { s.running = true for s.running { conn, err := s.listener.Accept() if err != nil { log.Error("accept error %s", err.Error()) continue } go s.onConn(conn) } return nil }
func (w *httpWriter) genericWrite(result interface{}) { m := map[string]interface{}{ w.cmd: result, } switch w.contentType { case "json": writeJSON(&m, w.w) case "bson": writeBSON(&m, w.w) case "msgpack": writeMsgPack(&m, w.w) default: log.Error("invalid content type %s", w.contentType) } }
func (m *master) startReplication(masterAddr string) error { //stop last replcation, if avaliable m.Close() if masterAddr != m.info.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 { l.Lock() defer l.Unlock() var err error if l.logFile == nil { if err = l.openNewLogFile(); err != nil { return err } } head := &BinLogHead{} head.CreateTime = uint32(time.Now().Unix()) head.BatchId = l.batchId l.batchId++ for _, data := range args { head.PayloadLen = uint32(len(data)) if err := head.Write(l.logWb); 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() close(l.ch) l.ch = make(chan struct{}) 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 }