github.com/gdamore/mangos@v1.4.0/message.go (about)

     1  // Copyright 2016 The Mangos Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mangos
    16  
    17  import (
    18  	"sync"
    19  	"sync/atomic"
    20  	"time"
    21  )
    22  
    23  // Message encapsulates the messages that we exchange back and forth.  The
    24  // meaning of the Header and Body fields, and where the splits occur, will
    25  // vary depending on the protocol.  Note however that any headers applied by
    26  // transport layers (including TCP/ethernet headers, and SP protocol
    27  // independent length headers), are *not* included in the Header.
    28  type Message struct {
    29  	// Header carries any protocol (SP) specific header.  Applications
    30  	// should not modify or use this unless they are using Raw mode.
    31  	// No user data may be placed here.
    32  	Header []byte
    33  
    34  	// Body carries the body of the message.  This can also be thought
    35  	// of as the message "payload".
    36  	Body []byte
    37  
    38  	// Port may be set on message receipt, to indicate the Port from
    39  	// which the Message was received.  There are no guarantees that the
    40  	// Port is still active, and applications should only use this for
    41  	// informational purposes.
    42  	Port Port
    43  
    44  	bbuf   []byte
    45  	hbuf   []byte
    46  	bsize  int
    47  	refcnt int32
    48  	expire time.Time
    49  	pool   *sync.Pool
    50  }
    51  
    52  type msgCacheInfo struct {
    53  	maxbody int
    54  	pool    *sync.Pool
    55  }
    56  
    57  func newMsg(sz int) *Message {
    58  	m := &Message{}
    59  	m.bbuf = make([]byte, 0, sz)
    60  	m.hbuf = make([]byte, 0, 32)
    61  	m.bsize = sz
    62  	return m
    63  }
    64  
    65  // We can tweak these!
    66  var messageCache = []msgCacheInfo{
    67  	{
    68  		maxbody: 64,
    69  		pool: &sync.Pool{
    70  			New: func() interface{} { return newMsg(64) },
    71  		},
    72  	}, {
    73  		maxbody: 128,
    74  		pool: &sync.Pool{
    75  			New: func() interface{} { return newMsg(128) },
    76  		},
    77  	}, {
    78  		maxbody: 256,
    79  		pool: &sync.Pool{
    80  			New: func() interface{} { return newMsg(256) },
    81  		},
    82  	}, {
    83  		maxbody: 512,
    84  		pool: &sync.Pool{
    85  			New: func() interface{} { return newMsg(512) },
    86  		},
    87  	}, {
    88  		maxbody: 1024,
    89  		pool: &sync.Pool{
    90  			New: func() interface{} { return newMsg(1024) },
    91  		},
    92  	}, {
    93  		maxbody: 4096,
    94  		pool: &sync.Pool{
    95  			New: func() interface{} { return newMsg(4096) },
    96  		},
    97  	}, {
    98  		maxbody: 8192,
    99  		pool: &sync.Pool{
   100  			New: func() interface{} { return newMsg(8192) },
   101  		},
   102  	}, {
   103  		maxbody: 65536,
   104  		pool: &sync.Pool{
   105  			New: func() interface{} { return newMsg(65536) },
   106  		},
   107  	},
   108  }
   109  
   110  // Free decrements the reference count on a message, and releases its
   111  // resources if no further references remain.  While this is not
   112  // strictly necessary thanks to GC, doing so allows for the resources to
   113  // be recycled without engaging GC.  This can have rather substantial
   114  // benefits for performance.
   115  func (m *Message) Free() {
   116  	if v := atomic.AddInt32(&m.refcnt, -1); v > 0 {
   117  		return
   118  	}
   119  	for i := range messageCache {
   120  		if m.bsize == messageCache[i].maxbody {
   121  			messageCache[i].pool.Put(m)
   122  			return
   123  		}
   124  	}
   125  }
   126  
   127  // Dup creates a "duplicate" message.  What it really does is simply
   128  // increment the reference count on the message.  Note that since the
   129  // underlying message is actually shared, consumers must take care not
   130  // to modify the message.  (We might revise this API in the future to
   131  // add a copy-on-write facility, but for now modification is neither
   132  // needed nor supported.)  Applications should *NOT* make use of this
   133  // function -- it is intended for Protocol, Transport and internal use only.
   134  func (m *Message) Dup() *Message {
   135  	atomic.AddInt32(&m.refcnt, 1)
   136  	return m
   137  }
   138  
   139  // Expired returns true if the message has "expired".  This is used by
   140  // transport implementations to discard messages that have been
   141  // stuck in the write queue for too long, and should be discarded rather
   142  // than delivered across the transport.  This is only used on the TX
   143  // path, there is no sense of "expiration" on the RX path.
   144  func (m *Message) Expired() bool {
   145  	if m.expire.IsZero() {
   146  		return false
   147  	}
   148  	if m.expire.After(time.Now()) {
   149  		return false
   150  	}
   151  	return true
   152  }
   153  
   154  // NewMessage is the supported way to obtain a new Message.  This makes
   155  // use of a "cache" which greatly reduces the load on the garbage collector.
   156  func NewMessage(sz int) *Message {
   157  	var m *Message
   158  	for i := range messageCache {
   159  		if sz < messageCache[i].maxbody {
   160  			m = messageCache[i].pool.Get().(*Message)
   161  			break
   162  		}
   163  	}
   164  	if m == nil {
   165  		m = newMsg(sz)
   166  	}
   167  
   168  	m.refcnt = 1
   169  	m.Body = m.bbuf
   170  	m.Header = m.hbuf
   171  	return m
   172  }