func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) { line, err := buf.UntilCRLF() if err != nil { debug("End of line not found, waiting for more data") return "", false, false, false } debug("line %s: %d", line, buf.BufferConsumed()) if len(line) == 3 && line[1] == '-' && line[2] == '1' { return "nil", false, true, true } if len(line) == 2 && line[1] == '0' { return "[]", false, true, true } count, err := strconv.ParseInt(string(line[1:]), 10, 64) if err != nil { logp.Err("Failed to read number of bulk messages: %s", err) return "", false, false, false } if count < 0 { return "nil", false, true, true } content := make([]string, 0, count) // read sub elements iserror := false for i := 0; i < int(count); i++ { var value string var ok, complete bool value, iserror, ok, complete := p.dispatch(depth+1, buf) if !ok || !complete { debug("Array incomplete") return "", iserror, ok, complete } content = append(content, value) } if depth == 0 && isRedisCommand(content[0]) { // we've got a request p.message.IsRequest = true p.message.Method = content[0] p.message.Path = content[1] } var value string if depth == 0 && p.message.IsRequest { value = strings.Join(content, " ") } else { value = "[" + strings.Join(content, ", ") + "]" } return value, iserror, true, true }
func parseVersionNumber(parser *parser, buf *streambuf.Buffer) parseResult { msg := parser.message if msg.IsRequest { return parser.contWith(buf, parseStateDataBinary) } // size already checked bytes, _ := buf.Collect(int(msg.bytes)) msg.str = memcacheString{bytes} return parser.yield(buf.BufferConsumed()) }
func (p *parser) parse(buf *streambuf.Buffer) (bool, bool) { snapshot := buf.Snapshot() content, iserror, ok, complete := p.dispatch(0, buf) if !ok || !complete { // on error or incomplete message drop all parsing progress, due to // parse not being statefull among multiple calls // => parser needs to restart parsing all content buf.Restore(snapshot) return ok, complete } p.message.isError = iserror p.message.size = buf.BufferConsumed() p.message.message = content return true, true }
func parseStatResponse(parser *parser, buf *streambuf.Buffer) parseResult { msg := parser.message if msg.IsRequest { return parser.contWith(buf, parseStateDataBinary) } bytes, _ := buf.Collect(int(msg.bytes)) if len(msg.keys) == 0 { return parser.failing(ErrExpectedKeys) } msg.stats = append(msg.stats, memcacheStat{ msg.keys[0], memcacheString{bytes}, }) return parser.yield(buf.BufferConsumed()) }
func parseDataBinary(parser *parser, buf *streambuf.Buffer) parseResult { msg := parser.message data, err := buf.Collect(int(msg.bytes - msg.bytesLost)) if err != nil { if err == streambuf.ErrNoMoreBytes { return parser.needMore() } return parser.failing(err) } debug("found data message") if msg.bytesLost > 0 { msg.count_values++ } else { parser.appendMessageData(data) } return parser.yield(buf.BufferConsumed() + int(msg.bytesLost)) }
func parseData(parser *parser, buf *streambuf.Buffer) parseResult { msg := parser.message debug("parse message data (%v)", msg.bytes) data, err := buf.CollectWithSuffix( int(msg.bytes-msg.bytesLost), []byte("\r\n"), ) if err != nil { if err == streambuf.ErrNoMoreBytes { return parser.needMore() } return parser.failing(err) } debug("found message data") if msg.bytesLost > 0 { msg.count_values++ } else { parser.appendMessageData(data) } return parser.yield(buf.BufferConsumed() + int(msg.bytesLost)) }
func parseBinaryCounterResponse( parser *parser, buf *streambuf.Buffer, ) parseResult { msg := parser.message if msg.IsRequest { return parser.contWith(buf, parseStateDataBinary) } // size already checked bytes, _ := buf.Collect(int(msg.bytes)) tmp := streambuf.NewFixed(bytes) err := withBinaryUint64(parser, tmp, func(msg *message, value uint64) { msg.value = value }) if err != nil { return parser.failing(err) } buf.Advance(8) return parser.yield(buf.BufferConsumed()) }
func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (common.NetString, bool, bool, bool) { line, err := buf.UntilCRLF() if err != nil { if isDebug { debugf("End of line not found, waiting for more data") } return empty, false, false, false } if isDebug { debugf("line %s: %d", line, buf.BufferConsumed()) } if len(line) == 3 && line[1] == '-' && line[2] == '1' { return nilStr, false, true, true } if len(line) == 2 && line[1] == '0' { return emptyArr, false, true, true } count, err := parseInt(line[1:]) if err != nil { logp.Err("Failed to read number of bulk messages: %s", err) return empty, false, false, false } if count < 0 { return nilStr, false, true, true } else if count == 0 { // should not happen, but handle just in case ParseInt did return 0 return emptyArr, false, true, true } // invariant: count > 0 // try to allocate content array right on stack var content [][]byte const arrayBufferSize = 32 if int(count) <= arrayBufferSize { var arrayBuffer [arrayBufferSize][]byte content = arrayBuffer[:0] } else { content = make([][]byte, 0, count) } contentLen := 0 // read sub elements iserror := false for i := 0; i < int(count); i++ { var value common.NetString var ok, complete bool value, iserror, ok, complete := p.dispatch(depth+1, buf) if !ok || !complete { if isDebug { debugf("Array incomplete") } return empty, iserror, ok, complete } content = append(content, []byte(value)) contentLen += len(value) } // handle top-level request command if depth == 0 && isRedisCommand(content[0]) { p.message.isRequest = true p.message.method = content[0] if len(content) > 1 { p.message.path = content[1] } var value common.NetString if contentLen > 1 { tmp := make([]byte, contentLen+(len(content)-1)*1) join(tmp, content, []byte(" ")) value = common.NetString(tmp) } else { value = common.NetString(content[0]) } return value, iserror, true, true } // return redis array: [a, b, c] tmp := make([]byte, 2+contentLen+(len(content)-1)*2) tmp[0] = '[' join(tmp[1:], content, []byte(", ")) tmp[len(tmp)-1] = ']' value := common.NetString(tmp) return value, iserror, true, true }
func (p *parser) yieldNoData(buf *streambuf.Buffer) parseResult { return p.yield(buf.BufferConsumed()) }