Beispiel #1
0
// Send a method frame out to the client
func (channel *Channel) SendContent(method amqp.MethodFrame, message *amqp.Message) {
	var start = stats.Start()
	channel.sendLock.Lock()
	defer channel.sendLock.Unlock()
	// encode header
	var buf = bytes.NewBuffer(make([]byte, 0, 20)) // todo: don't I know the size?
	amqp.WriteShort(buf, message.Header.ContentClass)
	amqp.WriteShort(buf, message.Header.ContentWeight)
	amqp.WriteLonglong(buf, message.Header.ContentBodySize)
	var propBuf = bytes.NewBuffer(make([]byte, 0, 20))
	flags, err := message.Header.Properties.WriteProps(propBuf)
	if err != nil {
		panic("Error writing header!")
	}
	amqp.WriteShort(buf, flags)
	buf.Write(propBuf.Bytes())
	stats.RecordHisto(channel.statSendEncode, start)
	start = stats.Start()
	// Send method
	channel.SendMethod(method)
	// Send header
	channel.outgoing <- &amqp.WireFrame{uint8(amqp.FrameHeader), channel.id, buf.Bytes()}
	// Send body
	for _, b := range message.Payload {
		b.Channel = channel.id
		channel.outgoing <- b
	}
	stats.RecordHisto(channel.statSendChan, start)
}
Beispiel #2
0
func (ms *MessageStore) RemoveRef(qm *amqp.QueueMessage, queueName string, rhs []amqp.MessageResourceHolder) error {
	defer stats.RecordHisto(ms.statRemoveRef, stats.Start())
	im, found := ms.GetIndex(qm.Id)
	if !found {
		panic("Integrity error: message in queue not in index")
	}
	if len(queueName) == 0 {
		panic("Bad queue name!")
	}
	// Update disk
	if im.Durable {
		ms.persistLock.Lock()
		ms.delOps[PersistKey{im.Id, queueName}] = qm
		ms.persistLock.Unlock()
	} else {
		// Update if only memory
		im.Refs -= 1
		if im.Refs == 0 {
			ms.msgLock.Lock()
			delete(ms.index, qm.Id)
			ms.msgLock.Unlock()

			ms.indexLock.Lock()
			delete(ms.messages, qm.Id)
			ms.indexLock.Unlock()
		}
	}

	for _, rh := range rhs {
		rh.ReleaseResources(qm)
	}
	return nil
}
Beispiel #3
0
func (ms *MessageStore) AddTxMessages(msgs []*amqp.TxMessage) (map[string][]*amqp.QueueMessage, error) {
	defer stats.RecordHisto(ms.statAdd, stats.Start())

	// - Figure out of any messages are durable
	// - Create IndexMessage instances for each message id
	anyDurable := false
	indexMessages := make(map[int64]*amqp.IndexMessage)
	queueMessages := make(map[string][]*amqp.QueueMessage)
	for _, msg := range msgs {
		// calc any durable
		var msgDurable = isDurable(msg.Msg)
		anyDurable = anyDurable || msgDurable
		// calc index messages
		var im, found = indexMessages[msg.Msg.Id]
		if !found {
			im = amqp.NewIndexMessage(msg.Msg.Id, 0, isDurable(msg.Msg), 0)
			indexMessages[msg.Msg.Id] = im
		}
		im.Refs += 1

		// calc queues
		queues, found := queueMessages[msg.QueueName]
		if !found {
			queues = make([]*amqp.QueueMessage, 0, 1)
		}
		qm := amqp.NewQueueMessage(
			msg.Msg.Id,
			0,
			msgDurable,
			messageSize(msg.Msg),
			msg.Msg.LocalId,
		)
		queueMessages[msg.QueueName] = append(queues, qm)
	}
	// if any are durable, persist those ones
	if anyDurable {
		ms.persistLock.Lock()
		for q, qms := range queueMessages {
			for _, qm := range qms {
				ms.addOps[PersistKey{qm.Id, q}] = qm
			}
		}
		ms.persistLock.Unlock()
	}
	// Add to memory message store
	ms.msgLock.Lock()
	defer ms.msgLock.Unlock()
	ms.indexLock.Lock()
	defer ms.indexLock.Unlock()
	for _, msg := range msgs {
		// fmt.Printf("Adding to index: %d\n", msg.Msg.Id)
		ms.index[msg.Msg.Id] = indexMessages[msg.Msg.Id]
		ms.messages[msg.Msg.Id] = msg.Msg
	}
	return queueMessages, nil
}
Beispiel #4
0
func (channel *Channel) basicPublish(method *amqp.BasicPublish) *amqp.AMQPError {
	defer stats.RecordHisto(channel.statPublish, stats.Start())
	var _, found = channel.server.exchanges[method.Exchange]
	if !found {
		var classId, methodId = method.MethodIdentifier()
		return amqp.NewSoftError(404, "Exchange not found", classId, methodId)
	}
	channel.startPublish(method)
	return nil
}
Beispiel #5
0
func (consumer *Consumer) consumeOne() {
	defer stats.RecordHisto(consumer.statConsumeOne, stats.Start())
	var err error
	// Check local limit
	consumer.consumeLock.Lock()
	defer consumer.consumeLock.Unlock()
	// Try to get message/check channel limit

	var start = stats.Start()
	var qm, msg = consumer.cqueue.GetOne(consumer.cchannel, consumer)
	stats.RecordHisto(consumer.statConsumeOneGetOne, start)
	if qm == nil {
		return
	}
	var tag uint64 = 0
	start = stats.Start()
	if !consumer.noAck {
		tag = consumer.cchannel.AddUnackedMessage(consumer.ConsumerTag, qm, consumer.queueName)
	} else {
		// We aren't expecting an ack, so this is the last time the message
		// will be referenced.
		var rhs = []amqp.MessageResourceHolder{consumer.cchannel, consumer}
		err = consumer.msgStore.RemoveRef(qm, consumer.queueName, rhs)
		if err != nil {
			panic("Error getting queue message")
		}
	}
	stats.RecordHisto(consumer.statConsumeOneAck, start)
	start = stats.Start()
	consumer.cchannel.SendContent(&amqp.BasicDeliver{
		ConsumerTag: consumer.ConsumerTag,
		DeliveryTag: tag,
		Redelivered: qm.DeliveryCount > 0,
		Exchange:    msg.Exchange,
		RoutingKey:  msg.Key,
	}, msg)
	stats.RecordHisto(consumer.statConsumeOneSend, start)
	consumer.StatCount += 1
	// Since we succeeded in processing a message, ping so that we try again
	consumer.Ping()
}
Beispiel #6
0
func (channel *Channel) handleContentBody(frame *amqp.WireFrame) *amqp.AMQPError {
	if channel.currentMessage == nil {
		return amqp.NewSoftError(500, "Unexpected content body frame. No method content-having method called yet!", 0, 0)
	}
	if channel.currentMessage.Header == nil {
		return amqp.NewSoftError(500, "Unexpected content body frame! No header yet", 0, 0)
	}
	channel.currentMessage.Payload = append(channel.currentMessage.Payload, frame)
	// TODO: store this on message
	var size = uint64(0)
	for _, body := range channel.currentMessage.Payload {
		size += uint64(len(body.Payload))
	}
	if size < channel.currentMessage.Header.ContentBodySize {
		return nil
	}

	// We have the whole contents, let's publish!
	defer stats.RecordHisto(channel.statRoute, stats.Start())
	var server = channel.server
	var message = channel.currentMessage

	exchange, _ := server.exchanges[message.Method.Exchange]

	if channel.txMode {
		// TxMode, add the messages to a list
		queues, err := exchange.QueuesForPublish(channel.currentMessage)
		if err != nil {
			return err
		}

		channel.txLock.Lock()
		for queueName, _ := range queues {
			var txmsg = amqp.NewTxMessage(message, queueName)
			channel.txMessages = append(channel.txMessages, txmsg)
		}
		channel.txLock.Unlock()
	} else {
		// Normal mode, publish directly
		returnMethod, amqpErr := server.publish(exchange, channel.currentMessage)
		if amqpErr != nil {
			channel.currentMessage = nil
			return amqpErr
		}
		if returnMethod != nil {
			channel.SendContent(returnMethod, channel.currentMessage)
		}
	}

	channel.currentMessage = nil
	return nil
}
Beispiel #7
0
func (q *Queue) processOne() {
	defer stats.RecordHisto(q.statProcOne, stats.Start())
	q.consumerLock.RLock()
	defer q.consumerLock.RUnlock()
	var size = len(q.consumers)
	if size == 0 {
		return
	}
	for count := 0; count < size; count++ {
		q.currentConsumer = (q.currentConsumer + 1) % size
		var c = q.consumers[q.currentConsumer]
		c.Ping()
	}
}