Exemplo n.º 1
0
func (resp *Response) Read(b *bufio.Reader) error {
	resp.items = make(map[string]*Item, 1)
	for {
		s, e := b.ReadString('\n')
		if e != nil {
			log.Print("read response line failed", e)
			return e
		}
		parts := strings.Fields(s)
		if len(parts) < 1 {
			return errors.New("invalid response")
		}

		resp.status = parts[0]
		switch resp.status {

		case "VALUE":
			if len(parts) < 3 {
				return errors.New("invalid response")
			}

			key := parts[1]
			// check key length
			length, e2 := strconv.Atoi(parts[2])
			if e2 != nil {
				return errors.New("invalid response")
			}
			if length > MaxBodyLength {
				return errors.New("body too large")
			}

			item := &Item{}
			// FIXME
			if length > AllocLimit {
				item.alloc = cmem.Alloc(uintptr(length))
				item.Body = (*[1 << 30]byte)(unsafe.Pointer(item.alloc))[:length]
				(*reflect.SliceHeader)(unsafe.Pointer(&item.Body)).Cap = length
				runtime.SetFinalizer(item, func(item *Item) {
					if item.alloc != nil {
						//log.Print("free by finalizer: ", cap(item.Body))
						cmem.Free(item.alloc, uintptr(cap(item.Body)))
						item.Body = nil
						item.alloc = nil
					}
				})
			} else {
				item.Body = make([]byte, length)
			}
			if _, e = io.ReadFull(b, item.Body); e != nil {
				return e
			}
			b.ReadByte() // \r
			b.ReadByte() // \n
			resp.items[key] = item
			continue

		case "STAT":
			if len(parts) != 3 {
				return errors.New("invalid response")
			}
			var item Item
			item.Body = []byte(parts[2])
			resp.items[parts[1]] = &item
			continue

		case "END":
		case "STORED", "NOT_STORED", "DELETED", "NOT_FOUND":
		case "OK":

		case "ERROR", "SERVER_ERROR", "CLIENT_ERROR":
			if len(parts) > 1 {
				resp.msg = parts[1]
			}
			log.Print("error:", resp)

		default:
			// try to convert to int
			_, err := strconv.Atoi(resp.status)
			if err != nil {
				log.Print("unknown status:", s, resp.status)
				return errors.New("unknown response:" + resp.status)
			}
		}
		break
	}
	return nil
}
Exemplo n.º 2
0
func (req *Request) Read(b *bufio.Reader) (e error) {
	var s string
	if s, e = b.ReadString('\n'); e != nil {
		return e
	}
	if !strings.HasSuffix(s, "\r\n") {
		return errors.New("not completed command")
	}
	parts := strings.Fields(s)
	if len(parts) < 1 {
		return errors.New("invalid cmd")
	}

	req.Cmd = parts[0]
	switch req.Cmd {

	case "get":
		if len(parts) != 2 {
			return errors.New("invalid cmd")
		}
		req.Key = parts[1]

	case "set":
		if len(parts) != 3 {
			return errors.New("invalid cmd")
		}
		req.Key = parts[1]
		req.Item = &Item{}
		item := req.Item
		length, e := strconv.Atoi(parts[2])
		if e != nil {
			return e
		}
		if length > MaxBodyLength {
			return errors.New("body too large")
		}
		// FIXME
		if length > AllocLimit {
			item.alloc = cmem.Alloc(uintptr(length))
			item.Body = (*[1 << 30]byte)(unsafe.Pointer(item.alloc))[:length]
			(*reflect.SliceHeader)(unsafe.Pointer(&item.Body)).Cap = length
			runtime.SetFinalizer(item, func(item *Item) {
				if item.alloc != nil {
					//log.Print("free by finalizer: ", cap(item.Body))
					cmem.Free(item.alloc, uintptr(cap(item.Body)))
					item.Body = nil
					item.alloc = nil
				}
			})
		} else {
			item.Body = make([]byte, length)
		}
		if _, e = io.ReadFull(b, item.Body); e != nil {
			return e
		}
		b.ReadByte() // \r
		b.ReadByte() // \n

	case "delete":
		if len(parts) != 2 {
			return errors.New("invalid cmd")
		}
		req.Key = parts[1]

	case "stats":
	case "quit", "version", "flush_all":
	default:
		log.Print("unknown command", req.Cmd)
		return errors.New("unknown command: " + req.Cmd)
	}

	return
}