Skip to content

Commit

Permalink
Merge pull request #556 from matheusd/fix-msg-seg-reuse
Browse files Browse the repository at this point in the history
message: Fix reuse of first segment
  • Loading branch information
lthibault authored Jul 19, 2024
2 parents 2f9aa4f + f0b2970 commit b1fc0ec
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 3 deletions.
12 changes: 9 additions & 3 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ func (m *Message) Release() {
func (m *Message) Reset(arena Arena) (first *Segment, err error) {
m.capTable.Reset()
for k := range m.segs {
// Optimization: keep the first segment so that the re-used
// Message does not have to allocate a new one.
if k == 0 && m.segs[k] == &m.firstSeg {
continue
}
delete(m.segs, k)
}

Expand All @@ -113,6 +118,7 @@ func (m *Message) Reset(arena Arena) (first *Segment, err error) {
DepthLimit: m.DepthLimit,
capTable: m.capTable,
segs: m.segs,
firstSeg: Segment{msg: m},
}

if arena != nil {
Expand Down Expand Up @@ -264,10 +270,10 @@ func (m *Message) Segment(id SegmentID) (*Segment, error) {
// segment returns the segment with the given ID, with no bounds
// checking. The caller must be holding m.mu.
func (m *Message) segment(id SegmentID) (*Segment, error) {
if m.segs == nil && id == 0 && m.firstSeg.msg != nil {
if m.segs == nil && id == 0 && m.firstSeg.msg != nil && m.firstSeg.data != nil {
return &m.firstSeg, nil
}
if s := m.segs[id]; s != nil {
if s := m.segs[id]; s != nil && s.data != nil {
return s, nil
}
if len(m.segs) == maxInt {
Expand Down Expand Up @@ -442,7 +448,7 @@ func alloc(s *Segment, sz Size) (*Segment, address, error) {
var err error
s, err = s.msg.allocSegment(sz)
if err != nil {
return nil, 0, err
return nil, 0, errors.New("allocSegment failed: " + err.Error())
}
}

Expand Down
18 changes: 18 additions & 0 deletions message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,3 +643,21 @@ func (readOnlyArena) Allocate(sz Size, segs map[SegmentID]*Segment) (SegmentID,
}

var errReadOnlyArena = errors.New("Allocate called on read-only arena")

func BenchmarkMessageGetFirstSegment(b *testing.B) {
var msg Message
var arena Arena = SingleSegment(nil)

b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, err := msg.Reset(arena)
if err != nil {
b.Fatal(err)
}
_, err = msg.Segment(0)
if err != nil {
b.Fatal(err)
}
}
}
2 changes: 2 additions & 0 deletions segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type SegmentID uint32
// It is part of a Message, which can contain other segments that
// reference each other.
type Segment struct {
// msg associated with this segment. A Message instance m maintains the
// invariant that that all m.segs[].msg == m.
msg *Message
id SegmentID
data []byte
Expand Down

0 comments on commit b1fc0ec

Please sign in to comment.