func (s *DefaultServer) Loop() { defer func() { if r := recover(); r != nil { if r != io.EOF { log.Println("Recovered from runtime panic:", r) log.Println("Panic location: ", identifyPanic()) } } }() for { start := time.Now() request, reqType, err := s.rp.Parse() if err != nil { if err == common.ErrBadRequest || err == common.ErrBadLength || err == common.ErrBadFlags || err == common.ErrBadExptime { s.orca.Error(nil, common.RequestUnknown, err) continue } else { // Otherwise IO error. Abort! abort(s.conns, err) return } } metrics.IncCounter(MetricCmdTotal) // TODO: handle nil switch reqType { case common.RequestSet: err = s.orca.Set(request.(common.SetRequest)) case common.RequestAdd: err = s.orca.Add(request.(common.SetRequest)) case common.RequestReplace: err = s.orca.Replace(request.(common.SetRequest)) case common.RequestDelete: err = s.orca.Delete(request.(common.DeleteRequest)) case common.RequestTouch: err = s.orca.Touch(request.(common.TouchRequest)) case common.RequestGet: err = s.orca.Get(request.(common.GetRequest)) case common.RequestGetE: err = s.orca.GetE(request.(common.GetRequest)) case common.RequestGat: err = s.orca.Gat(request.(common.GATRequest)) case common.RequestNoop: err = s.orca.Noop(request.(common.NoopRequest)) case common.RequestQuit: s.orca.Quit(request.(common.QuitRequest)) abort(s.conns, err) return case common.RequestVersion: err = s.orca.Version(request.(common.VersionRequest)) case common.RequestUnknown: err = s.orca.Unknown(request) } if err != nil { if common.IsAppError(err) { if err != common.ErrKeyNotFound { metrics.IncCounter(MetricErrAppError) } s.orca.Error(request, reqType, err) } else { metrics.IncCounter(MetricErrUnrecoverable) abort(s.conns, err) return } } dur := uint64(time.Since(start)) switch reqType { case common.RequestSet: metrics.ObserveHist(HistSet, dur) case common.RequestAdd: metrics.ObserveHist(HistAdd, dur) case common.RequestReplace: metrics.ObserveHist(HistReplace, dur) case common.RequestDelete: metrics.ObserveHist(HistDelete, dur) case common.RequestTouch: metrics.ObserveHist(HistTouch, dur) case common.RequestGet: metrics.ObserveHist(HistGet, dur) case common.RequestGetE: metrics.ObserveHist(HistGetE, dur) case common.RequestGat: metrics.ObserveHist(HistGat, dur) } } }
func handleConnectionReal(remoteConn net.Conn, l1, l2 handlers.Handler) { remoteReader := bufio.NewReader(remoteConn) remoteWriter := bufio.NewWriter(remoteConn) var reqParser common.RequestParser var responder common.Responder var reqType common.RequestType var request interface{} binaryParser := binprot.NewBinaryParser(remoteReader) binaryResponder := binprot.NewBinaryResponder(remoteWriter) textParser := textprot.NewTextParser(remoteReader) textResponder := textprot.NewTextResponder(remoteWriter) for { binary, err := isBinaryRequest(remoteReader) if err != nil { abort([]io.Closer{remoteConn, l1, l2}, err, binary) return } if binary { reqParser = binaryParser responder = binaryResponder } else { reqParser = textParser responder = textResponder } request, reqType, err = reqParser.Parse() if err != nil { abort([]io.Closer{remoteConn, l1, l2}, err, binary) return } // TODO: handle nil switch reqType { case common.RequestSet: req := request.(common.SetRequest) //fmt.Println("set", string(req.Key)) err = l1.Set(req, remoteReader) if err == nil { responder.Set() } case common.RequestDelete: req := request.(common.DeleteRequest) //fmt.Println("delete", string(req.Key)) err = l1.Delete(req) if err == nil { responder.Delete() } case common.RequestTouch: req := request.(common.TouchRequest) //fmt.Println("touch", string(req.Key)) err = l1.Touch(req) if err == nil { responder.Touch() } case common.RequestGet: req := request.(common.GetRequest) //debugString := "get" //for _, k := range req.Keys { // debugString += " " // debugString += string(k) //} //println(debugString) resChan, errChan := l1.Get(req) for { select { case res, ok := <-resChan: if !ok { resChan = nil } else { if res.Miss { responder.GetMiss(res) } else { responder.Get(res) } } case getErr, ok := <-errChan: if !ok { errChan = nil } else { err = getErr } } if resChan == nil && errChan == nil { break } } if err == nil { responder.GetEnd(req.NoopEnd) } case common.RequestGat: req := request.(common.GATRequest) //fmt.Println("gat", string(req.Key)) res, err := l1.GAT(req) if err == nil { if res.Miss { responder.GATMiss(res) } else { responder.GAT(res) responder.GetEnd(false) } } case common.RequestUnknown: err = common.ErrUnknownCmd } // TODO: distinguish fatal errors from non-fatal if err != nil { if common.IsAppError(err) { responder.Error(err) } else { abort([]io.Closer{remoteConn, l1, l2}, err, binary) return } } } }