func getMetadataCommon(rw *bufio.ReadWriter) (metadata, error) { if err := rw.Flush(); err != nil { return metadata{}, err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return metadata{}, err } err = binprot.DecodeError(resHeader) if err != nil { // read in the message "Not found" after a miss if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return metadata{}, ioerr } return metadata{}, err } serverFlags := make([]byte, 4) binary.Read(rw, binary.BigEndian, &serverFlags) var metaData metadata binary.Read(rw, binary.BigEndian, &metaData) return metaData, nil }
func simpleCmdLocal(rw *bufio.ReadWriter) error { if err := rw.Flush(); err != nil { return err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return err } err = binprot.DecodeError(resHeader) if err != nil { if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return ioerr } return err } // Read in the message bytes from the body if _, err := rw.Discard(int(resHeader.TotalBodyLength)); err != nil { return err } return nil }
func simpleCmdLocal(rw *bufio.ReadWriter) error { if err := rw.Flush(); err != nil { return err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return err } defer binprot.PutResponseHeader(resHeader) err = binprot.DecodeError(resHeader) if err != nil { n, ioerr := rw.Discard(int(resHeader.TotalBodyLength)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) if ioerr != nil { return ioerr } return err } // Read in the message bytes from the body n, err := rw.Discard(int(resHeader.TotalBodyLength)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) return err }
func getLocal(rw *bufio.ReadWriter) (data []byte, flags uint32, err error) { if err := rw.Flush(); err != nil { return nil, 0, err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return nil, 0, err } err = binprot.DecodeError(resHeader) if err != nil { if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return nil, 0, ioerr } return nil, 0, err } var serverFlags uint32 binary.Read(rw, binary.BigEndian, &serverFlags) // total body - key - extra dataLen := resHeader.TotalBodyLength - uint32(resHeader.KeyLength) - uint32(resHeader.ExtraLength) buf := make([]byte, dataLen) // Read in value if _, err := io.ReadFull(rw, buf); err != nil { return nil, 0, err } return buf, serverFlags, nil }
func getLocalIntoBuf(rw *bufio.ReadWriter, cmd []byte, tokenBuf []byte, buf []byte, totalDataLength int) error { if _, err := rw.Write(cmd); err != nil { return err } if err := rw.Flush(); err != nil { return err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return err } err = binprot.DecodeError(resHeader) if err != nil { if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return ioerr } return err } serverFlags := make([]byte, 4) binary.Read(rw, binary.BigEndian, &serverFlags) // Read in token if requested if tokenBuf != nil { if _, err := io.ReadFull(rw, tokenBuf); err != nil { return err } } // Read in value if _, err := io.ReadFull(rw, buf); err != nil { return err } // consume padding at end of chunk if needed if len(buf) < totalDataLength { if _, ioerr := rw.Discard(totalDataLength - len(buf)); ioerr != nil { return ioerr } } return nil }
func getLocal(rw *bufio.ReadWriter, readExp bool) (data []byte, flags, exp uint32, err error) { if err := rw.Flush(); err != nil { return nil, 0, 0, err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return nil, 0, 0, err } defer binprot.PutResponseHeader(resHeader) err = binprot.DecodeError(resHeader) if err != nil { n, ioerr := rw.Discard(int(resHeader.TotalBodyLength)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) if ioerr != nil { return nil, 0, 0, ioerr } return nil, 0, 0, err } var serverFlags uint32 binary.Read(rw, binary.BigEndian, &serverFlags) metrics.IncCounterBy(common.MetricBytesReadLocal, 4) var serverExp uint32 if readExp { binary.Read(rw, binary.BigEndian, &serverExp) metrics.IncCounterBy(common.MetricBytesReadLocal, 4) } // total body - key - extra dataLen := resHeader.TotalBodyLength - uint32(resHeader.KeyLength) - uint32(resHeader.ExtraLength) buf := make([]byte, dataLen) // Read in value n, err := io.ReadAtLeast(rw, buf, int(dataLen)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) if err != nil { return nil, 0, 0, err } return buf, serverFlags, serverExp, nil }
func getMetadataCommon(rw *bufio.ReadWriter) (metadata, error) { if err := rw.Flush(); err != nil { return emptyMeta, err } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return emptyMeta, err } defer binprot.PutResponseHeader(resHeader) err = binprot.DecodeError(resHeader) if err != nil { // read in the message "Not found" after a miss n, ioerr := rw.Discard(int(resHeader.TotalBodyLength)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) if ioerr != nil { return emptyMeta, ioerr } return emptyMeta, err } // we currently do nothing with the flags //buf := make([]byte, 4) //n, err := io.ReadAtLeast(rw, buf, 4) //metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) //if err != nil { // return emptyMeta, err //} //serverFlags := binary.BigEndian.Uint32(buf) // instead of reading and parsing flags, just discard rw.Discard(4) metrics.IncCounterBy(common.MetricBytesReadLocal, 4) metaData, err := readMetadata(rw) if err != nil { return emptyMeta, err } return metaData, nil }
func simpleCmdLocal(rw *bufio.ReadWriter, flush bool) error { if flush { if err := rw.Flush(); err != nil { return err } } resHeader, err := binprot.ReadResponseHeader(rw) if err != nil { return err } n, ioerr := rw.Discard(int(resHeader.TotalBodyLength)) metrics.IncCounterBy(common.MetricBytesReadLocal, uint64(n)) if ioerr != nil { binprot.PutResponseHeader(resHeader) return ioerr } binprot.PutResponseHeader(resHeader) return binprot.DecodeError(resHeader) }
func HandleSet(cmd common.SetRequest, src *bufio.Reader, rw *bufio.ReadWriter) error { // For writing chunks, the specialized chunked reader is appropriate. // for unchunked, a limited reader will be needed since the text protocol // includes a /r/n at the end and there's no EOF to be had with a long-l`ived // connection. limChunkReader := stream.NewChunkLimitedReader(src, int64(CHUNK_SIZE), int64(cmd.Length)) numChunks := int(math.Ceil(float64(cmd.Length) / float64(CHUNK_SIZE))) token := <-tokens metaKey := metaKey(cmd.Key) metaData := common.Metadata{ Length: cmd.Length, OrigFlags: cmd.Flags, NumChunks: uint32(numChunks), ChunkSize: CHUNK_SIZE, Token: token, } metaDataBuf := new(bytes.Buffer) binary.Write(metaDataBuf, binary.BigEndian, metaData) // Write metadata key // TODO: should there be a unique flags value for chunked data? localCmd := binprot.SetCmd(metaKey, cmd.Flags, cmd.Exptime, common.METADATA_SIZE) if err := setLocal(rw.Writer, localCmd, metaDataBuf); err != nil { return err } // Read server's response resHeader, err := readResponseHeader(rw.Reader) if err != nil { // Discard request body if _, ioerr := src.Discard(int(cmd.Length)); ioerr != nil { return ioerr } // Discard response body if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return ioerr } return err } // Write all the data chunks // TODO: Clean up if a data chunk write fails // Failure can mean the write failing at the I/O level // or at the memcached level, e.g. response == ERROR chunkNum := 0 for limChunkReader.More() { // Build this chunk's key key := chunkKey(cmd.Key, chunkNum) // Write the key localCmd = binprot.SetCmd(key, cmd.Flags, cmd.Exptime, FULL_DATA_SIZE) if err = setLocalWithToken(rw.Writer, localCmd, token, limChunkReader); err != nil { return err } // Read server's response resHeader, err = readResponseHeader(rw.Reader) if err != nil { // Discard request body for limChunkReader.More() { if _, ioerr := io.Copy(ioutil.Discard, limChunkReader); ioerr != nil { return ioerr } limChunkReader.NextChunk() } // Discard repsonse body if _, ioerr := rw.Discard(int(resHeader.TotalBodyLength)); ioerr != nil { return ioerr } return err } // Reset for next iteration limChunkReader.NextChunk() chunkNum++ } return nil }