Ejemplo n.º 1
0
func (req *Request) Clear() {
	req.NoReply = false
	if req.Item != nil && req.Item.alloc != nil {
		cmem.Free(req.Item.alloc, uintptr(cap(req.Item.Body)))
		req.Item.Body = nil
		req.Item.alloc = nil
		req.Item = nil
	}
}
Ejemplo n.º 2
0
func (resp *Response) CleanBuffer() {
	for _, item := range resp.items {
		if item.alloc != nil {
			cmem.Free(item.alloc, uintptr(cap(item.Body)))
			item.alloc = nil
		}
		runtime.SetFinalizer(item, nil)
	}
	resp.items = nil
}
Ejemplo n.º 3
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) < 4 {
				return errors.New("invalid response")
			}

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

			item := &Item{Flag: flag}
			if len(parts) == 5 {
				cas, e := strconv.Atoi(parts[4])
				if e != nil {
					return errors.New("invalid response")
				}
				item.Cas = cas
			}

			// 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 {
				// response from incr,decr
				resp.msg = resp.status
				resp.status = "INCR"
			} else {
				log.Print("unknown status:", s, resp.status)
				return errors.New("unknown response:" + resp.status)
			}
		}
		break
	}
	return nil
}
Ejemplo n.º 4
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", "gets":
		if len(parts) < 2 {
			return errors.New("invalid cmd")
		}
		req.Keys = parts[1:]

	case "set", "add", "replace", "cas", "append", "prepend":
		if len(parts) < 5 || len(parts) > 7 {
			return errors.New("invalid cmd")
		}
		req.Keys = parts[1:2]
		req.Item = &Item{}
		item := req.Item
		item.Flag, e = strconv.Atoi(parts[2])
		if e != nil {
			return e
		}
		item.Exptime, e = strconv.Atoi(parts[3])
		if e != nil {
			return e
		}
		length, e := strconv.Atoi(parts[4])
		if e != nil {
			return e
		}
		if length > MaxBodyLength {
			return errors.New("body too large")
		}
		if req.Cmd == "cas" {
			if len(parts) < 6 {
				return errors.New("invalid cmd")
			}
			item.Cas, e = strconv.Atoi(parts[5])
			if len(parts) > 6 && parts[6] != "noreply" {
				return errors.New("invalid cmd")
			}
			req.NoReply = len(parts) > 6 && parts[6] == "noreply"
		} else {
			if len(parts) > 5 && parts[5] != "noreply" {
				return errors.New("invalid cmd")
			}
			req.NoReply = len(parts) > 5 && parts[5] == "noreply"
		}

		// 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 || len(parts) > 4 {
			return errors.New("invalid cmd")
		}
		req.Keys = parts[1:2]
		req.NoReply = len(parts) > 2 && parts[len(parts)-1] == "noreply"

	case "incr", "decr":
		if len(parts) < 3 || len(parts) > 4 {
			return errors.New("invalid cmd")
		}
		req.Keys = parts[1:2]
		req.Item = &Item{Body: []byte(parts[2])}
		req.NoReply = len(parts) > 3 && parts[3] == "noreply"

	case "stats":
		req.Keys = parts[1:]

	case "quit", "version", "flush_all":
	case "verbosity":
		if len(parts) >= 2 {
			req.Keys = parts[1:]
		}

	default:
		log.Print("unknown command", req.Cmd)
		return errors.New("unknown command: " + req.Cmd)
	}

	return
}