summaryrefslogtreecommitdiffhomepage
path: root/pkg/p9/messages.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/p9/messages.go')
-rw-r--r--pkg/p9/messages.go232
1 files changed, 131 insertions, 101 deletions
diff --git a/pkg/p9/messages.go b/pkg/p9/messages.go
index 833defbd6..3c7898cc1 100644
--- a/pkg/p9/messages.go
+++ b/pkg/p9/messages.go
@@ -193,6 +193,7 @@ func (t *Twalk) Decode(b *buffer) {
t.FID = b.ReadFID()
t.NewFID = b.ReadFID()
n := b.Read16()
+ t.Names = t.Names[:0]
for i := 0; i < int(n); i++ {
t.Names = append(t.Names, b.ReadString())
}
@@ -227,6 +228,7 @@ type Rwalk struct {
// Decode implements encoder.Decode.
func (r *Rwalk) Decode(b *buffer) {
n := b.Read16()
+ r.QIDs = r.QIDs[:0]
for i := 0; i < int(n); i++ {
var q QID
q.Decode(b)
@@ -1608,6 +1610,7 @@ type Rreaddir struct {
func (r *Rreaddir) Decode(b *buffer) {
r.Count = b.Read32()
entriesBuf := buffer{data: r.payload}
+ r.Entries = r.Entries[:0]
for {
var d Dirent
d.Decode(&entriesBuf)
@@ -1827,6 +1830,7 @@ func (t *Twalkgetattr) Decode(b *buffer) {
t.FID = b.ReadFID()
t.NewFID = b.ReadFID()
n := b.Read16()
+ t.Names = t.Names[:0]
for i := 0; i < int(n); i++ {
t.Names = append(t.Names, b.ReadString())
}
@@ -1869,6 +1873,7 @@ func (r *Rwalkgetattr) Decode(b *buffer) {
r.Valid.Decode(b)
r.Attr.Decode(b)
n := b.Read16()
+ r.QIDs = r.QIDs[:0]
for i := 0; i < int(n); i++ {
var q QID
q.Decode(b)
@@ -2139,34 +2144,80 @@ func (r *Rlconnect) String() string {
return fmt.Sprintf("Rlconnect{File: %v}", r.File)
}
-// messageRegistry indexes all messages by type.
-var messageRegistry = make([]func() message, math.MaxUint8)
+const maxCacheSize = 3
-// messageByType creates a new message by type.
+// msgFactory is used to reduce allocations by caching messages for reuse.
+type msgFactory struct {
+ create func() message
+ cache chan message
+}
+
+// msgRegistry indexes all message factories by type.
+var msgRegistry registry
+
+type registry struct {
+ factories [math.MaxUint8]msgFactory
+
+ // largestFixedSize is computed so that given some message size M, you can
+ // compute the maximum payload size (e.g. for Twrite, Rread) with
+ // M-largestFixedSize. You could do this individual on a per-message basis,
+ // but it's easier to compute a single maximum safe payload.
+ largestFixedSize uint32
+}
+
+// get returns a new message by type.
//
// An error is returned in the case of an unknown message.
//
// This takes, and ignores, a message tag so that it may be used directly as a
// lookupTagAndType function for recv (by design).
-func messageByType(_ Tag, t MsgType) (message, error) {
- fn := messageRegistry[t]
- if fn == nil {
+func (r *registry) get(_ Tag, t MsgType) (message, error) {
+ entry := &r.factories[t]
+ if entry.create == nil {
return nil, &ErrInvalidMsgType{t}
}
- return fn(), nil
+
+ select {
+ case msg := <-entry.cache:
+ return msg, nil
+ default:
+ return entry.create(), nil
+ }
+}
+
+func (r *registry) put(msg message) {
+ if p, ok := msg.(payloader); ok {
+ p.SetPayload(nil)
+ }
+ if f, ok := msg.(filer); ok {
+ f.SetFilePayload(nil)
+ }
+
+ entry := &r.factories[msg.Type()]
+ select {
+ case entry.cache <- msg:
+ default:
+ }
}
// register registers the given message type.
//
// This may cause panic on failure and should only be used from init.
-func register(t MsgType, fn func() message) {
- if int(t) >= len(messageRegistry) {
- panic(fmt.Sprintf("message type %d is too large. It must be smaller than %d", t, len(messageRegistry)))
+func (r *registry) register(t MsgType, fn func() message) {
+ if int(t) >= len(r.factories) {
+ panic(fmt.Sprintf("message type %d is too large. It must be smaller than %d", t, len(r.factories)))
}
- if messageRegistry[t] != nil {
- panic(fmt.Sprintf("duplicate message type %d: first is %T, second is %T", t, messageRegistry[t](), fn()))
+ if r.factories[t].create != nil {
+ panic(fmt.Sprintf("duplicate message type %d: first is %T, second is %T", t, r.factories[t].create(), fn()))
+ }
+ r.factories[t] = msgFactory{
+ create: fn,
+ cache: make(chan message, maxCacheSize),
+ }
+
+ if size := calculateSize(fn()); size > r.largestFixedSize {
+ r.largestFixedSize = size
}
- messageRegistry[t] = fn
}
func calculateSize(m message) uint32 {
@@ -2178,93 +2229,72 @@ func calculateSize(m message) uint32 {
return uint32(len(dataBuf.data))
}
-// largestFixedSize is computed within calculateLargestSize.
-//
-// This is computed so that given some message size M, you can compute
-// the maximum payload size (e.g. for Twrite, Rread) with M-largestFixedSize.
-// You could do this individual on a per-message basis, but it's easier to
-// compute a single maximum safe payload.
-var largestFixedSize uint32
-
-// calculateLargestFixedSize is called from within init.
-func calculateLargestFixedSize() {
- for _, fn := range messageRegistry {
- if fn != nil {
- if size := calculateSize(fn()); size > largestFixedSize {
- largestFixedSize = size
- }
- }
- }
-}
-
func init() {
- register(MsgRlerror, func() message { return &Rlerror{} })
- register(MsgTstatfs, func() message { return &Tstatfs{} })
- register(MsgRstatfs, func() message { return &Rstatfs{} })
- register(MsgTlopen, func() message { return &Tlopen{} })
- register(MsgRlopen, func() message { return &Rlopen{} })
- register(MsgTlcreate, func() message { return &Tlcreate{} })
- register(MsgRlcreate, func() message { return &Rlcreate{} })
- register(MsgTsymlink, func() message { return &Tsymlink{} })
- register(MsgRsymlink, func() message { return &Rsymlink{} })
- register(MsgTmknod, func() message { return &Tmknod{} })
- register(MsgRmknod, func() message { return &Rmknod{} })
- register(MsgTrename, func() message { return &Trename{} })
- register(MsgRrename, func() message { return &Rrename{} })
- register(MsgTreadlink, func() message { return &Treadlink{} })
- register(MsgRreadlink, func() message { return &Rreadlink{} })
- register(MsgTgetattr, func() message { return &Tgetattr{} })
- register(MsgRgetattr, func() message { return &Rgetattr{} })
- register(MsgTsetattr, func() message { return &Tsetattr{} })
- register(MsgRsetattr, func() message { return &Rsetattr{} })
- register(MsgTxattrwalk, func() message { return &Txattrwalk{} })
- register(MsgRxattrwalk, func() message { return &Rxattrwalk{} })
- register(MsgTxattrcreate, func() message { return &Txattrcreate{} })
- register(MsgRxattrcreate, func() message { return &Rxattrcreate{} })
- register(MsgTreaddir, func() message { return &Treaddir{} })
- register(MsgRreaddir, func() message { return &Rreaddir{} })
- register(MsgTfsync, func() message { return &Tfsync{} })
- register(MsgRfsync, func() message { return &Rfsync{} })
- register(MsgTlink, func() message { return &Tlink{} })
- register(MsgRlink, func() message { return &Rlink{} })
- register(MsgTmkdir, func() message { return &Tmkdir{} })
- register(MsgRmkdir, func() message { return &Rmkdir{} })
- register(MsgTrenameat, func() message { return &Trenameat{} })
- register(MsgRrenameat, func() message { return &Rrenameat{} })
- register(MsgTunlinkat, func() message { return &Tunlinkat{} })
- register(MsgRunlinkat, func() message { return &Runlinkat{} })
- register(MsgTversion, func() message { return &Tversion{} })
- register(MsgRversion, func() message { return &Rversion{} })
- register(MsgTauth, func() message { return &Tauth{} })
- register(MsgRauth, func() message { return &Rauth{} })
- register(MsgTattach, func() message { return &Tattach{} })
- register(MsgRattach, func() message { return &Rattach{} })
- register(MsgTflush, func() message { return &Tflush{} })
- register(MsgRflush, func() message { return &Rflush{} })
- register(MsgTwalk, func() message { return &Twalk{} })
- register(MsgRwalk, func() message { return &Rwalk{} })
- register(MsgTread, func() message { return &Tread{} })
- register(MsgRread, func() message { return &Rread{} })
- register(MsgTwrite, func() message { return &Twrite{} })
- register(MsgRwrite, func() message { return &Rwrite{} })
- register(MsgTclunk, func() message { return &Tclunk{} })
- register(MsgRclunk, func() message { return &Rclunk{} })
- register(MsgTremove, func() message { return &Tremove{} })
- register(MsgRremove, func() message { return &Rremove{} })
- register(MsgTflushf, func() message { return &Tflushf{} })
- register(MsgRflushf, func() message { return &Rflushf{} })
- register(MsgTwalkgetattr, func() message { return &Twalkgetattr{} })
- register(MsgRwalkgetattr, func() message { return &Rwalkgetattr{} })
- register(MsgTucreate, func() message { return &Tucreate{} })
- register(MsgRucreate, func() message { return &Rucreate{} })
- register(MsgTumkdir, func() message { return &Tumkdir{} })
- register(MsgRumkdir, func() message { return &Rumkdir{} })
- register(MsgTumknod, func() message { return &Tumknod{} })
- register(MsgRumknod, func() message { return &Rumknod{} })
- register(MsgTusymlink, func() message { return &Tusymlink{} })
- register(MsgRusymlink, func() message { return &Rusymlink{} })
- register(MsgTlconnect, func() message { return &Tlconnect{} })
- register(MsgRlconnect, func() message { return &Rlconnect{} })
-
- calculateLargestFixedSize()
+ msgRegistry.register(MsgRlerror, func() message { return &Rlerror{} })
+ msgRegistry.register(MsgTstatfs, func() message { return &Tstatfs{} })
+ msgRegistry.register(MsgRstatfs, func() message { return &Rstatfs{} })
+ msgRegistry.register(MsgTlopen, func() message { return &Tlopen{} })
+ msgRegistry.register(MsgRlopen, func() message { return &Rlopen{} })
+ msgRegistry.register(MsgTlcreate, func() message { return &Tlcreate{} })
+ msgRegistry.register(MsgRlcreate, func() message { return &Rlcreate{} })
+ msgRegistry.register(MsgTsymlink, func() message { return &Tsymlink{} })
+ msgRegistry.register(MsgRsymlink, func() message { return &Rsymlink{} })
+ msgRegistry.register(MsgTmknod, func() message { return &Tmknod{} })
+ msgRegistry.register(MsgRmknod, func() message { return &Rmknod{} })
+ msgRegistry.register(MsgTrename, func() message { return &Trename{} })
+ msgRegistry.register(MsgRrename, func() message { return &Rrename{} })
+ msgRegistry.register(MsgTreadlink, func() message { return &Treadlink{} })
+ msgRegistry.register(MsgRreadlink, func() message { return &Rreadlink{} })
+ msgRegistry.register(MsgTgetattr, func() message { return &Tgetattr{} })
+ msgRegistry.register(MsgRgetattr, func() message { return &Rgetattr{} })
+ msgRegistry.register(MsgTsetattr, func() message { return &Tsetattr{} })
+ msgRegistry.register(MsgRsetattr, func() message { return &Rsetattr{} })
+ msgRegistry.register(MsgTxattrwalk, func() message { return &Txattrwalk{} })
+ msgRegistry.register(MsgRxattrwalk, func() message { return &Rxattrwalk{} })
+ msgRegistry.register(MsgTxattrcreate, func() message { return &Txattrcreate{} })
+ msgRegistry.register(MsgRxattrcreate, func() message { return &Rxattrcreate{} })
+ msgRegistry.register(MsgTreaddir, func() message { return &Treaddir{} })
+ msgRegistry.register(MsgRreaddir, func() message { return &Rreaddir{} })
+ msgRegistry.register(MsgTfsync, func() message { return &Tfsync{} })
+ msgRegistry.register(MsgRfsync, func() message { return &Rfsync{} })
+ msgRegistry.register(MsgTlink, func() message { return &Tlink{} })
+ msgRegistry.register(MsgRlink, func() message { return &Rlink{} })
+ msgRegistry.register(MsgTmkdir, func() message { return &Tmkdir{} })
+ msgRegistry.register(MsgRmkdir, func() message { return &Rmkdir{} })
+ msgRegistry.register(MsgTrenameat, func() message { return &Trenameat{} })
+ msgRegistry.register(MsgRrenameat, func() message { return &Rrenameat{} })
+ msgRegistry.register(MsgTunlinkat, func() message { return &Tunlinkat{} })
+ msgRegistry.register(MsgRunlinkat, func() message { return &Runlinkat{} })
+ msgRegistry.register(MsgTversion, func() message { return &Tversion{} })
+ msgRegistry.register(MsgRversion, func() message { return &Rversion{} })
+ msgRegistry.register(MsgTauth, func() message { return &Tauth{} })
+ msgRegistry.register(MsgRauth, func() message { return &Rauth{} })
+ msgRegistry.register(MsgTattach, func() message { return &Tattach{} })
+ msgRegistry.register(MsgRattach, func() message { return &Rattach{} })
+ msgRegistry.register(MsgTflush, func() message { return &Tflush{} })
+ msgRegistry.register(MsgRflush, func() message { return &Rflush{} })
+ msgRegistry.register(MsgTwalk, func() message { return &Twalk{} })
+ msgRegistry.register(MsgRwalk, func() message { return &Rwalk{} })
+ msgRegistry.register(MsgTread, func() message { return &Tread{} })
+ msgRegistry.register(MsgRread, func() message { return &Rread{} })
+ msgRegistry.register(MsgTwrite, func() message { return &Twrite{} })
+ msgRegistry.register(MsgRwrite, func() message { return &Rwrite{} })
+ msgRegistry.register(MsgTclunk, func() message { return &Tclunk{} })
+ msgRegistry.register(MsgRclunk, func() message { return &Rclunk{} })
+ msgRegistry.register(MsgTremove, func() message { return &Tremove{} })
+ msgRegistry.register(MsgRremove, func() message { return &Rremove{} })
+ msgRegistry.register(MsgTflushf, func() message { return &Tflushf{} })
+ msgRegistry.register(MsgRflushf, func() message { return &Rflushf{} })
+ msgRegistry.register(MsgTwalkgetattr, func() message { return &Twalkgetattr{} })
+ msgRegistry.register(MsgRwalkgetattr, func() message { return &Rwalkgetattr{} })
+ msgRegistry.register(MsgTucreate, func() message { return &Tucreate{} })
+ msgRegistry.register(MsgRucreate, func() message { return &Rucreate{} })
+ msgRegistry.register(MsgTumkdir, func() message { return &Tumkdir{} })
+ msgRegistry.register(MsgRumkdir, func() message { return &Rumkdir{} })
+ msgRegistry.register(MsgTumknod, func() message { return &Tumknod{} })
+ msgRegistry.register(MsgRumknod, func() message { return &Rumknod{} })
+ msgRegistry.register(MsgTusymlink, func() message { return &Tusymlink{} })
+ msgRegistry.register(MsgRusymlink, func() message { return &Rusymlink{} })
+ msgRegistry.register(MsgTlconnect, func() message { return &Tlconnect{} })
+ msgRegistry.register(MsgRlconnect, func() message { return &Rlconnect{} })
}