func (feed *DcpFeed) doDcpGetFailoverLog( opaque uint16, vblist []uint16, rcvch chan []interface{}) (map[uint16]*FailoverLog, error) { rq := &transport.MCRequest{ Opcode: transport.DCP_FAILOVERLOG, Opaque: opaqueFailover, } failoverLogs := make(map[uint16]*FailoverLog) for _, vBucket := range vblist { rq.VBucket = vBucket if err := feed.conn.Transmit(rq); err != nil { fmsg := "%v ##%x doDcpGetFailoverLog.Transmit(): %v" logging.Errorf(fmsg, feed.logPrefix, opaque, err) return nil, err } msg, ok := <-rcvch if !ok { fmsg := "%v ##%x doDcpGetFailoverLog.rcvch closed" logging.Errorf(fmsg, feed.logPrefix, opaque) return nil, ErrorConnection } pkt := msg[0].(*transport.MCRequest) req := &transport.MCResponse{ Opcode: pkt.Opcode, Cas: pkt.Cas, Opaque: pkt.Opaque, Status: transport.Status(pkt.VBucket), Extras: pkt.Extras, Key: pkt.Key, Body: pkt.Body, } if req.Opcode != transport.DCP_FAILOVERLOG { fmsg := "%v ##%x for failover log request unexpected #opcode %v" logging.Errorf(fmsg, feed.logPrefix, opaque, req.Opcode) return nil, ErrorInvalidFeed } else if req.Status != transport.SUCCESS { fmsg := "%v ##%x for failover log request unexpected #status %v" logging.Errorf(fmsg, feed.logPrefix, opaque, req.Status) return nil, ErrorInvalidFeed } flog, err := parseFailoverLog(req.Body) if err != nil { fmsg := "%v ##%x parse failover logs for vb %d" logging.Errorf(fmsg, feed.logPrefix, opaque, vBucket) return nil, ErrorInvalidFeed } failoverLogs[vBucket] = flog } return failoverLogs, nil }
func (feed *DcpFeed) doDcpGetSeqnos( rcvch chan []interface{}) (map[uint16]uint64, error) { rq := &transport.MCRequest{ Opcode: transport.DCP_GET_SEQNO, Opaque: opaqueGetseqno, } if err := feed.conn.Transmit(rq); err != nil { fmsg := "%v ##%x doDcpGetSeqnos.Transmit(): %v" logging.Errorf(fmsg, feed.logPrefix, rq.Opaque, err) return nil, err } msg, ok := <-rcvch if !ok { fmsg := "%v ##%x doDcpGetSeqnos.rcvch closed" logging.Errorf(fmsg, feed.logPrefix, rq.Opaque) return nil, ErrorConnection } pkt := msg[0].(*transport.MCRequest) req := &transport.MCResponse{ Opcode: pkt.Opcode, Cas: pkt.Cas, Opaque: pkt.Opaque, Status: transport.Status(pkt.VBucket), Extras: pkt.Extras, Key: pkt.Key, Body: pkt.Body, } if req.Opcode != transport.DCP_GET_SEQNO { fmsg := "%v ##%x for get-seqno request unexpected #opcode %v" logging.Errorf(fmsg, feed.logPrefix, req.Opaque, req.Opcode) return nil, ErrorInvalidFeed } else if req.Status != transport.SUCCESS { fmsg := "%v ##%x for get-seqno request unexpected #status %v" logging.Errorf(fmsg, feed.logPrefix, req.Opaque, req.Status) return nil, ErrorInvalidFeed } seqnos, err := parseGetSeqnos(req.Body) if err != nil { fmsg := "%v ##%x parsing get-seqnos: %v" logging.Errorf(fmsg, feed.logPrefix, req.Opaque, err) return nil, ErrorInvalidFeed } return seqnos, nil }
func (feed *DcpFeed) doDcpOpen( name string, sequence, bufsize uint32, opaque uint16, rcvch chan []interface{}) error { rq := &transport.MCRequest{ Opcode: transport.DCP_OPEN, Key: []byte(name), Opaque: opaqueOpen, } rq.Extras = make([]byte, 8) binary.BigEndian.PutUint32(rq.Extras[:4], sequence) binary.BigEndian.PutUint32(rq.Extras[4:], 1) // we are consumer prefix := feed.logPrefix if err := feed.conn.Transmit(rq); err != nil { return err } msg, ok := <-rcvch if !ok { logging.Errorf("%v ##%x doDcpOpen.rcvch closed", prefix, opaque) return ErrorConnection } pkt := msg[0].(*transport.MCRequest) req := &transport.MCResponse{ Opcode: pkt.Opcode, Cas: pkt.Cas, Opaque: pkt.Opaque, Status: transport.Status(pkt.VBucket), Extras: pkt.Extras, Key: pkt.Key, Body: pkt.Body, } if req.Opcode != transport.DCP_OPEN { logging.Errorf("%v ##%x unexpected #%v", prefix, opaque, req.Opcode) return ErrorConnection } else if rq.Opaque != req.Opaque { fmsg := "%v ##%x opaque mismatch, %v != %v" logging.Errorf(fmsg, prefix, opaque, req.Opaque, req.Opaque) return ErrorConnection } else if req.Status != transport.SUCCESS { fmsg := "%v ##%x doDcpOpen response status %v" logging.Errorf(fmsg, prefix, opaque, req.Status) return ErrorConnection } // send a DCP control message to set the window size for // this connection if bufsize > 0 { rq := &transport.MCRequest{ Opcode: transport.DCP_CONTROL, Key: []byte("connection_buffer_size"), Body: []byte(strconv.Itoa(int(bufsize))), } if err := feed.conn.Transmit(rq); err != nil { fmsg := "%v ##%x doDcpOpen.DCP_CONTROL.Transmit(): %v" logging.Errorf(fmsg, prefix, opaque, err) return err } msg, ok := <-rcvch if !ok { fmsg := "%v ##%x doDcpOpen.DCP_CONTROL.rcvch closed" logging.Errorf(fmsg, prefix, opaque) return ErrorConnection } pkt := msg[0].(*transport.MCRequest) req := &transport.MCResponse{ Opcode: pkt.Opcode, Cas: pkt.Cas, Opaque: pkt.Opaque, Status: transport.Status(pkt.VBucket), Extras: pkt.Extras, Key: pkt.Key, Body: pkt.Body, } if req.Opcode != transport.DCP_CONTROL { fmsg := "%v ##%x DCP_CONTROL != #%v" logging.Errorf(fmsg, prefix, opaque, req.Opcode) return ErrorConnection } else if req.Status != transport.SUCCESS { fmsg := "%v ##%x doDcpOpen response status %v" logging.Errorf(fmsg, prefix, opaque, req.Status) return ErrorConnection } feed.maxAckBytes = uint32(bufferAckThreshold * float32(bufsize)) } return nil }
func (feed *DcpFeed) handlePacket( pkt *transport.MCRequest, bytes int) string { var event *DcpEvent feed.stats.TotalBytes += uint64(bytes) res := &transport.MCResponse{ Opcode: pkt.Opcode, Cas: pkt.Cas, Opaque: pkt.Opaque, Status: transport.Status(pkt.VBucket), Extras: pkt.Extras, Key: pkt.Key, Body: pkt.Body, } vb := vbOpaque(pkt.Opaque) sendAck := false prefix := feed.logPrefix stream := feed.vbstreams[vb] if stream == nil { fmsg := "%v spurious %v for %d: %#v\n" logging.Fatalf(fmsg, prefix, pkt.Opcode, vb, pkt) return "ok" // yeah it not _my_ mistake... } stream.LastSeen = time.Now().UnixNano() switch pkt.Opcode { case transport.DCP_STREAMREQ: event = newDcpEvent(pkt, stream) feed.handleStreamRequest(res, vb, stream, event) case transport.DCP_MUTATION, transport.DCP_DELETION, transport.DCP_EXPIRATION: event = newDcpEvent(pkt, stream) stream.Seqno = event.Seqno feed.stats.TotalMutation++ sendAck = true case transport.DCP_STREAMEND: event = newDcpEvent(pkt, stream) sendAck = true delete(feed.vbstreams, vb) fmsg := "%v ##%x DCP_STREAMEND for vb %d\n" logging.Debugf(fmsg, prefix, stream.AppOpaque, vb) case transport.DCP_SNAPSHOT: event = newDcpEvent(pkt, stream) event.SnapstartSeq = binary.BigEndian.Uint64(pkt.Extras[0:8]) event.SnapendSeq = binary.BigEndian.Uint64(pkt.Extras[8:16]) event.SnapshotType = binary.BigEndian.Uint32(pkt.Extras[16:20]) stream.Snapstart = event.SnapstartSeq stream.Snapend = event.SnapendSeq feed.stats.TotalSnapShot++ sendAck = true fmsg := "%v ##%x DCP_SNAPSHOT for vb %d\n" logging.Debugf(fmsg, prefix, stream.AppOpaque, vb) case transport.DCP_FLUSH: event = newDcpEvent(pkt, stream) // special processing ? case transport.DCP_CLOSESTREAM: event = newDcpEvent(pkt, stream) if event.Opaque != stream.CloseOpaque { fmsg := "%v ##%x DCP_CLOSESTREAM mismatch in opaque %v != %v\n" logging.Fatalf( fmsg, prefix, stream.AppOpaque, event.Opaque, stream.CloseOpaque) } event.Opcode = transport.DCP_STREAMEND // opcode re-write !! event.Opaque = stream.AppOpaque // opaque re-write !! sendAck = true delete(feed.vbstreams, vb) fmsg := "%v ##%x DCP_CLOSESTREAM for vb %d\n" logging.Debugf(fmsg, prefix, stream.AppOpaque, vb) case transport.DCP_CONTROL, transport.DCP_BUFFERACK: if res.Status != transport.SUCCESS { fmsg := "%v ##%x opcode %v received status %v\n" logging.Errorf(fmsg, prefix, stream.AppOpaque, pkt.Opcode, res.Status) } case transport.DCP_NOOP: noop := &transport.MCRequest{Opcode: transport.DCP_NOOP} if err := feed.conn.Transmit(noop); err != nil { // send a NOOP back logging.Errorf("%v NOOP.Transmit(): %v", prefix, err) } case transport.DCP_ADDSTREAM: fmsg := "%v ##%x opcode DCP_ADDSTREAM not implemented\n" logging.Fatalf(fmsg, prefix, stream.AppOpaque) default: fmsg := "%v opcode %v not known for vbucket %d\n" logging.Warnf(fmsg, prefix, pkt.Opcode, vb) } if event != nil { feed.outch <- event } feed.sendBufferAck(sendAck, uint32(bytes)) return "ok" }