// 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) }
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 }
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 }
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 }
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() }
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 }
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() } }