// 从Client读取数据 func (s *Session) loopReader(tasks chan<- *Request, d Dispatcher) error { if d == nil { return errors.New("nil dispatcher") } for !s.quit { // client <--> rpc // 从client读取frames request, err := s.ReadFrame() if err != nil { err1, ok := err.(thrift.TTransportException) if !ok || err1.TypeId() != thrift.END_OF_FILE { // 遇到EOF等错误,就直接结束loopReader // 结束之前需要和后端的back_conn之间处理好关系? log.ErrorErrorf(err, Red("ReadFrame Error: %v"), err) } return err } r, err := s.handleRequest(request, d) if err != nil { return err } else { if s.verbose { log.Info("Succeed Get Result") } // 将请求交给: tasks, 同一个Session中的请求是 tasks <- r } } return nil }
// 配对 Request, resp, err // PARAM: resp []byte 为一帧完整的thrift数据包 func (bc *BackendConnLB) setResponse(r *Request, data []byte, err error) error { // 表示出现错误了 if data == nil { log.Printf("No Data From Server, error: %v\n", err) r.Response.Err = err } else { // 从resp中读取基本的信息 typeId, seqId, err := DecodeThriftTypIdSeqId(data) // 解码错误,直接报错 if err != nil { return err } if typeId == MESSAGE_TYPE_STOP { // 不再接受新的输入 // 直接来自后端的服务(不遵循: Request/Reply模型) bc.MarkConnActiveFalse() return nil } // 找到对应的Request bc.Lock() req, ok := bc.seqNum2Request[seqId] if ok { delete(bc.seqNum2Request, seqId) } bc.Unlock() // 如果是心跳,则OK if typeId == MESSAGE_TYPE_HEART_BEAT { bc.hbLastTime.Set(time.Now().Unix()) return nil } if !ok { return errors.New("Invalid Response") } // log.Printf("Data From Server, seqId: %d, Request: %d\n", seqId, req.Request.SeqId) r = req r.Response.TypeId = typeId } r.Response.Data, r.Response.Err = data, err // 还原SeqId if data != nil { r.RestoreSeqId() } // 设置几个控制用的channel if err != nil && r.Failed != nil { r.Failed.Set(true) } if r.Wait != nil { r.Wait.Done() } return err }
// 配对 Request, resp, err // PARAM: resp []byte 为一帧完整的thrift数据包 func (bc *BackendConn) setResponse(r *Request, data []byte, err error) error { // 表示出现错误了 if data == nil { log.Printf("[%s]No Data From Server, error: %v", r.Service, err) r.Response.Err = err } else { // 从resp中读取基本的信息 typeId, seqId, err := DecodeThriftTypIdSeqId(data) // 解码错误,直接报错 if err != nil { return err } // 找到对应的Request bc.Lock() req, ok := bc.seqNum2Request[seqId] if ok { delete(bc.seqNum2Request, seqId) } bc.Unlock() // 如果是心跳,则OK if typeId == MESSAGE_TYPE_HEART_BEAT { // log.Printf(Magenta("Get Ping/Pang Back")) bc.hbLastTime.Set(time.Now().Unix()) return nil } if !ok { return errors.New("Invalid Response") } if bc.verbose { log.Printf("[%s]Data From Server, seqId: %d, Request: %d", req.Service, seqId, req.Request.SeqId) } r = req r.Response.TypeId = typeId } r.Response.Data, r.Response.Err = data, err // 还原SeqId if data != nil { r.RestoreSeqId() } // 设置几个控制用的channel if err != nil && r.Failed != nil { r.Failed.Set(true) } if r.Wait != nil { r.Wait.Done() } return err }
const ( B = 1 << (10 * iota) KB MB GB TB PB ) var ( BytesizeRegexp = regexp.MustCompile(`(?i)^\s*(\-?[\d\.]+)\s*([KMGTP]?B|[BKMGTP]|)\s*$`) digitsRegexp = regexp.MustCompile(`^\-?\d+$`) ) var ( ErrBadBytesize = errors.New("invalid byte size") ErrBadBytesizeUnit = errors.New("invalid byte size unit") ) func Parse(s string) (int64, error) { if !BytesizeRegexp.MatchString(s) { return 0, errors.Trace(ErrBadBytesize) } subs := BytesizeRegexp.FindStringSubmatch(s) if len(subs) != 3 { return 0, errors.Trace(ErrBadBytesize) } size := int64(0) switch strings.ToUpper(string(subs[2])) {
// // 将 bc.input 中的Request写入后端的服务器 // func (bc *BackendConn) loopWriter(c *TBufferedFramedTransport) error { bc.hbTicker = time.NewTicker(time.Second) defer func() { bc.hbTicker.Stop() bc.hbStop <- true }() bc.MarkConnActiveOK() // 准备接受数据 bc.loopReader(c) // 异步 bc.Heartbeat() // 建立连接之后,就启动HB var r *Request var ok bool for true { // 等待输入的Event, 或者 heartbeatTimeout select { case r, ok = <-bc.input: if !ok { return nil } case <-bc.hbTimeout: return errors.New(fmt.Sprintf("[%s]HB timeout", bc.service)) } // // 如果暂时没有数据输入,则p策略可能就有问题了 // 只有写入数据,才有可能产生flush; 如果是最后一个数据必须自己flush, 否则就可能无限期等待 // if r.Request.TypeId == MESSAGE_TYPE_HEART_BEAT { // 过期的HB信号,直接放弃 if time.Now().Unix()-r.Start > 4 { continue } } // 请求正常转发给后端的Rpc Server var flush = len(bc.input) == 0 // if bc.verbose { // fmt.Printf("Force flush %t", flush) // } // 1. 替换新的SeqId r.ReplaceSeqId(bc.currentSeqId) // 2. 主动控制Buffer的flush c.Write(r.Request.Data) err := c.FlushBuffer(flush) if err == nil { // log.Printf("Succeed Write Request to backend Server/LB\n") bc.IncreaseCurrentSeqId() bc.Lock() bc.seqNum2Request[r.Response.SeqId] = r bc.Unlock() } else { // 进入不可用状态(不可用状态下,通过自我心跳进入可用状态) return bc.setResponse(r, nil, err) } } return nil }
func NewRollingFile(basePath string, logKeepDays int) (io.WriteCloser, error) { if logKeepDays <= 0 { return nil, errors.Errorf("invalid max file-frag = %d", logKeepDays) } if _, file := path.Split(basePath); file == "" { return nil, errors.Errorf("invalid base-path = %s, file name is required", basePath) } return &rollingFile{ logKeepDays: logKeepDays, basePath: basePath, nextStartOfDate: nextStartOfDay(time.Now()), }, nil } var ErrClosedRollingFile = errors.New("rolling file is closed") func (r *rollingFile) roll() error { if r.file != nil { // 还没有日期切换 now := time.Now() if now.Before(r.nextStartOfDate) { return nil } r.file.Close() r.file = nil r.nextStartOfDate = nextStartOfDay(now) // 将logKeepDays之前几天的日志删除 for i := r.logKeepDays; i < r.logKeepDays+4; i++ {
// // 数据: LB ---> backend services // // 如果input关闭,且loopWriter正常处理完毕之后,返回nil // 其他情况返回error // func (bc *BackendConnLB) loopWriter() error { // 正常情况下, ok总是为True; 除非bc.input的发送者主动关闭了channel, 表示再也没有新的Task过来了 // 参考: https://tour.golang.org/concurrency/4 // 如果input没有关闭,则会block c := NewTBufferedFramedTransport(bc.transport, 100*time.Microsecond, 20) // bc.MarkConnActiveOK() // 准备接受数据 // BackendConnLB 在构造之初就有打开的transport, 并且Active默认为OK bc.hbTicker = time.NewTicker(time.Second) defer func() { bc.hbTicker.Stop() bc.hbStop <- true }() bc.loopReader(c) // 异步 bc.Heartbeat() // 建立连接之后,就启动HB var r *Request var ok bool for true { // 等待输入的Event, 或者 heartbeatTimeout select { case r, ok = <-bc.input: if !ok { return nil } case <-bc.hbTimeout: return errors.New("HB timeout") } // 如果暂时没有数据输入,则p策略可能就有问题了 // 只有写入数据,才有可能产生flush; 如果是最后一个数据必须自己flush, 否则就可能无限期等待 // if r.Request.TypeId == MESSAGE_TYPE_HEART_BEAT { // 过期的HB信号,直接放弃 if time.Now().Unix()-r.Start > 4 { continue } else { // log.Printf(Magenta("Send Heartbeat to %s\n"), bc.Addr4Log()) } } var flush = len(bc.input) == 0 // fmt.Printf("Force flush %t\n", flush) // 1. 替换新的SeqId r.ReplaceSeqId(bc.currentSeqId) // 2. 主动控制Buffer的flush // log.Printf("Request Data Len: %d\n ", len(r.Request.Data)) c.Write(r.Request.Data) err := c.FlushBuffer(flush) if err == nil { bc.IncreaseCurrentSeqId() bc.Lock() bc.seqNum2Request[r.Response.SeqId] = r bc.Unlock() // 继续读取请求, 如果有异常,如何处理呢? } else { log.ErrorErrorf(err, "FlushBuffer Error: %v\n", err) // 进入不可用状态(不可用状态下,通过自我心跳进入可用状态) return bc.setResponse(r, nil, err) } } return nil }