Example #1
0
func doTap(b Bucket, req *gomemcached.MCRequest, r io.Reader,
	chpkt chan<- transmissible, cherr <-chan error) *gomemcached.MCResponse {
	tc, err := req.ParseTapCommands()
	if err != nil {
		return &gomemcached.MCResponse{
			Status: gomemcached.EINVAL,
			Body:   []byte(fmt.Sprintf("ParseTapCommands err: %v", err)),
		}
	}

	// TODO: TAP of a vbucket list.

	res, yesDump := tapFlagBool(&tc, gomemcached.DUMP)
	if res != nil {
		return res
	}
	if yesDump || tapFlagExists(&tc, gomemcached.BACKFILL) {
		res := doTapBackFill(b, req, r, chpkt, cherr, tc)
		if res != nil {
			return res
		}
		if yesDump {
			close(chpkt)
			return &gomemcached.MCResponse{Fatal: true}
		}
	}

	// TODO: There's probably a mutation gap between backfill and tap-forward.

	return doTapForward(b, req, r, chpkt, cherr, tc)
}
Example #2
0
func sendGet(key string) {
	req := gomemcached.MCRequest{
		Opcode:  gomemcached.GET,
		Cas:     938424885,
		Opaque:  7242,
		VBucket: 824,
		Extras:  []byte{},
		Key:     []byte(key),
		Body:    []byte{},
	}

	conn, _ := net.Dial("tcp", "localhost:9955")

	conn.Write(req.Bytes())

	res := gomemcached.MCResponse{}
	_, err := res.Receive(bufio.NewReader(conn), nil)
	if err != nil {
		fmt.Println("Error: ", err.Error())
	}
	fmt.Println(res.String())
	value := string(res.Body[:len(res.Body)])
	fmt.Println(value)
	conn.Close()

}
Example #3
0
func doReceive(
	uprconn *uprConnection, host string, msgch chan msgT, killSwitch chan bool) {

	var hdr [mcd.HDR_LEN]byte
	var msg msgT
	var pkt mcd.MCRequest
	var err error

	mcconn := uprconn.conn.Hijack()

loop:
	for {
		if _, err = pkt.Receive(mcconn, hdr[:]); err != nil {
			msg = msgT{uprconn: uprconn, err: err}
		} else {
			msg = msgT{uprconn: uprconn, pkt: pkt}
		}
		select {
		case msgch <- msg:
		case <-killSwitch:
			break loop
		}
	}
	return
}
Example #4
0
// UPR_FAILOVER_LOG, synchronous call.
func (client *Client) UprFailOverLog(
	req *mc.MCRequest) ([][2]uint64, error) {

	req.Opcode = UPR_FAILOVER_LOG // #OpCode
	req.Opaque = 0xDEADBEEF       // #Opaque
	req.Key = []byte{}            // #Key
	req.Extras = []byte{}         // #Extras

	// Trasmit the request
	if err := client.conn.Transmit(req); err != nil {
		return nil, err
	}

	res := <-client.response // Wait for response from doRecieve()
	if res.Opcode != UPR_FAILOVER_LOG {
		err := fmt.Errorf("UprFailOverLog: unexpected #opcode", res.Opcode)
		return nil, err
	} else if req.Opaque != res.Opaque {
		err := fmt.Errorf(
			"UprFailOverLog: #opaque mismatch", req.Opaque, res.Opaque)
		return nil, err
	} else if len(res.Body)%16 != 0 {
		err := fmt.Errorf(
			"UprFailOverLog: Invalide body of length", len(res.Body))
		return nil, err
	} else if res.Status != mc.SUCCESS {
		return nil, fmt.Errorf("UprOpen: Status", res.Status)
	}

	// Return the log
	return parseFailoverLog(res.Body), nil
}
Example #5
0
// UPR_OPEN, synchronous call.
func (client *Client) UprOpen(
	req *mc.MCRequest, name string, seqNo, flags uint32) error {

	if len(name) > 65535 {
		log.Panicln("UprOpen: name cannot exceed 65535")
	}

	req.Opcode = UPR_OPEN  // #OpCode
	req.Key = []byte(name) // #Key
	req.Extras = make([]byte, 8)
	binary.BigEndian.PutUint32(req.Extras[:4], seqNo)
	// #Extras.sequenceNo
	// while consumer is opening the connection Type flag needs to be cleared.
	binary.BigEndian.PutUint32(req.Extras[4:], flags)
	// #Extras.flags

	// Trasmit the request
	if err := client.conn.Transmit(req); err != nil {
		return err
	}
	client.name = name

	res := <-client.response // Wait for response from doRecieve()
	if res == nil {
		return fmt.Errorf("UprOpen: closed")
	} else if res.Opcode != UPR_OPEN {
		return fmt.Errorf("UprOpen: unexpected #opcode", res.Opcode)
	} else if req.Opaque != res.Opaque {
		return fmt.Errorf("UprOpen: #opaque mismatch", req.Opaque, res.Opaque)
	} else if res.Status != mc.SUCCESS {
		return fmt.Errorf("UprOpen: Status", res.Status)
	}
	return nil
}
Example #6
0
// Internal goroutine that reads from the socket and writes events to
// the channel
func (mc *Client) runFeed(ch chan TapEvent, feed *TapFeed) {
	defer close(ch)
	var headerBuf [gomemcached.HDR_LEN]byte
loop:
	for {
		// Read the next request from the server.
		//
		//  (Can't call mc.Receive() because it reads a
		//  _response_ not a request.)
		var pkt gomemcached.MCRequest
		n, err := pkt.Receive(mc.conn, headerBuf[:])
		if TapRecvHook != nil {
			TapRecvHook(&pkt, n, err)
		}

		if err != nil {
			if err != io.EOF {
				feed.Error = err
			}
			break loop
		}

		//log.Printf("** TapFeed received %#v : %q", pkt, pkt.Body)

		if pkt.Opcode == gomemcached.TAP_CONNECT {
			// This is not an event from the server; it's
			// an error response to my connect request.
			feed.Error = fmt.Errorf("tap connection failed: %s", pkt.Body)
			break loop
		}

		event := makeTapEvent(pkt)
		if event != nil {
			if event.Opcode == tapEndStream {
				break loop
			}

			select {
			case ch <- *event:
			case <-feed.closer:
				break loop
			}
		}

		if len(pkt.Extras) >= 4 {
			reqFlags := binary.BigEndian.Uint16(pkt.Extras[2:])
			if reqFlags&gomemcached.TAP_ACK != 0 {
				if _, err := mc.sendAck(&pkt); err != nil {
					feed.Error = err
					break loop
				}
			}
		}
	}
	if err := mc.Close(); err != nil {
		log.Printf("Error closing memcached client:  %v", err)
	}
}
Example #7
0
func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (int, error) {
	if o == nil {
		return 0, errNoConn
	}
	n, err := req.Transmit(o)
	if TransmitHook != nil {
		TransmitHook(req, n, err)
	}
	return n, err
}
Example #8
0
func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (err error) {
	if len(req.Body) < 128 {
		_, err = o.Write(req.Bytes())
	} else {
		_, err = o.Write(req.HeaderBytes())
		if err == nil && len(req.Body) > 0 {
			_, err = o.Write(req.Body)
		}
	}
	return
}
Example #9
0
func TestTransmitReq(t *testing.T) {
	b := bytes.NewBuffer([]byte{})
	buf := bufio.NewWriter(b)

	req := gomemcached.MCRequest{
		Opcode:  gomemcached.SET,
		Cas:     938424885,
		Opaque:  7242,
		VBucket: 824,
		Extras:  []byte{},
		Key:     []byte("somekey"),
		Body:    []byte("somevalue"),
	}

	// Verify nil transmit is OK
	_, err := transmitRequest(nil, &req)
	if err != errNoConn {
		t.Errorf("Expected errNoConn with no conn, got %v", err)
	}

	_, err = transmitRequest(buf, &req)
	if err != nil {
		t.Fatalf("Error transmitting request: %v", err)
	}

	buf.Flush()

	expected := []byte{
		gomemcached.REQ_MAGIC, byte(gomemcached.SET),
		0x0, 0x7, // length of key
		0x0,       // extra length
		0x0,       // reserved
		0x3, 0x38, // vbucket
		0x0, 0x0, 0x0, 0x10, // Length of value
		0x0, 0x0, 0x1c, 0x4a, // opaque
		0x0, 0x0, 0x0, 0x0, 0x37, 0xef, 0x3a, 0x35, // CAS
		's', 'o', 'm', 'e', 'k', 'e', 'y',
		's', 'o', 'm', 'e', 'v', 'a', 'l', 'u', 'e'}

	if len(b.Bytes()) != req.Size() {
		t.Fatalf("Expected %v bytes, got %v", req.Size(),
			len(b.Bytes()))
	}

	if !reflect.DeepEqual(b.Bytes(), expected) {
		t.Fatalf("Expected:\n%#v\n  -- got -- \n%#v",
			expected, b.Bytes())
	}
}
Example #10
0
func BenchmarkTransmitReqNull(b *testing.B) {
	req := gomemcached.MCRequest{
		Opcode:  gomemcached.SET,
		Cas:     938424885,
		Opaque:  7242,
		VBucket: 824,
		Extras:  []byte{},
		Key:     []byte("somekey"),
		Body:    []byte("somevalue"),
	}

	b.SetBytes(int64(req.Size()))

	for i := 0; i < b.N; i++ {
		err := transmitRequest(ioutil.Discard, &req)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}
Example #11
0
func BenchmarkTransmitReqLarge(b *testing.B) {
	bout := bytes.NewBuffer([]byte{})

	req := gomemcached.MCRequest{
		Opcode:  gomemcached.SET,
		Cas:     938424885,
		Opaque:  7242,
		VBucket: 824,
		Extras:  []byte{},
		Key:     []byte("somekey"),
		Body:    make([]byte, 24*1024),
	}

	b.SetBytes(int64(req.Size()))

	for i := 0; i < b.N; i++ {
		bout.Reset()
		buf := bufio.NewWriterSize(bout, req.Size()*2)
		err := transmitRequest(buf, &req)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}
Example #12
0
func sendUnknownCommand() {
	req := gomemcached.MCRequest{
		Opcode:  gomemcached.ADD,
		Cas:     938424885,
		Opaque:  7242,
		VBucket: 824,
		Extras:  []byte{},
		Key:     []byte("key"),
		Body:    []byte("somevalue"),
	}

	conn, _ := net.Dial("tcp", "localhost:9955")

	conn.Write(req.Bytes())

	res := gomemcached.MCResponse{}
	_, err := res.Receive(bufio.NewReader(conn), nil)
	if err != nil {
		fmt.Println("Error: ", err.Error())
	}
	fmt.Println(res.String())
	conn.Close()

}
Example #13
0
func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (err error) {
	if o == nil {
		return noConn
	}
	return req.Transmit(o)
}
Example #14
0
func transmitRequest(o io.Writer, req *gomemcached.MCRequest) (err error) {
	_, err = o.Write(req.Bytes())
	return
}
Example #15
0
// UPR_STREAM_REQ, synchronous call.
func (client *Client) UprStream(
	req *mc.MCRequest, flags uint32,
	startSeqno, endSeqno, vuuid, highSeqno uint64) (*Stream, uint64, error) {

	req.Opcode = UPR_STREAM_REQ // #OpCode
	// #Opaque
	req.Key = []byte{} // #Keys
	req.Extras = make([]byte, 40)
	binary.BigEndian.PutUint32(req.Extras[:4], flags)
	binary.BigEndian.PutUint32(req.Extras[4:8], uint32(0))
	binary.BigEndian.PutUint64(req.Extras[8:16], startSeqno)
	binary.BigEndian.PutUint64(req.Extras[16:24], endSeqno)
	binary.BigEndian.PutUint64(req.Extras[24:32], vuuid)
	binary.BigEndian.PutUint64(req.Extras[32:40], highSeqno)
	// #Extras

	stream := client.NewStream(req.VBucket, vuuid, req.Opaque)
	client.addStream(req.Opaque, stream)

	if client.conn != nil {
		if err := client.conn.Transmit(req); err != nil { // Transmit request
			return nil, 0, err
		}
	} else {
		err := fmt.Errorf("Trying to open a stream on a closed connection")
		return nil, 0, err
	}

	res := <-client.response // Wait for response
	if res == nil {
		return nil, 0, errors.New("closed")
	} else if res.Opcode != UPR_STREAM_REQ {
		err := fmt.Errorf("UprStream: unexpected #opcode", res.Opcode)
		return nil, 0, err
	} else if req.Opaque != res.Opaque {
		err := fmt.Errorf("UprStream: #opaque mismatch", req.Opaque, res.Opaque)
		return nil, 0, err
	}

	// If not success, remove the Stream reference from client connection,
	// that was optimistically added above.
	if res.Status != mc.SUCCESS {
		client.evictStream(req.Opaque)
	}

	// Check whether it is rollback
	var err error

	switch res.Status {
	case mc.SUCCESS:
		stream.Log = parseFailoverLog(res.Body)
		log.Println("Stream req ", stream.Log)
		return stream, 0, err
	case ROLLBACK:
		if len(res.Extras) != 8 {
			err = fmt.Errorf("UprStream: Invalid rollback", res.Extras)
		}
		rollback := binary.BigEndian.Uint64(res.Extras)
		return nil, rollback, err
	default:
		return nil, 0, fmt.Errorf("UprStream: Status", res.Status)
	}
}