Skip to content

Commit 18dc4db

Browse files
authored
Merge pull request pkg#343 from drakkan/allocations
fileget: allocate a slice with enough capacity
2 parents 0e12323 + 0a45bc4 commit 18dc4db

File tree

3 files changed

+18
-9
lines changed

3 files changed

+18
-9
lines changed

packet.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,13 @@ func (p *sshFxpReadPacket) UnmarshalBinary(b []byte) error {
584584
return nil
585585
}
586586

587+
func (p *sshFxpReadPacket) getDataSlice() []byte {
588+
dataLen := clamp(p.Len, maxTxPacket)
589+
// we allocate a slice with a bigger capacity so we avoid a new allocation in sshFxpDataPacket.MarshalBinary
590+
// and in sendPacket, we need 9 bytes in MarshalBinary and 4 bytes in sendPacket
591+
return make([]byte, dataLen, dataLen+9+4)
592+
}
593+
587594
type sshFxpRenamePacket struct {
588595
ID uint32
589596
Oldpath string
@@ -819,11 +826,14 @@ type sshFxpDataPacket struct {
819826
Data []byte
820827
}
821828

829+
// MarshalBinary encodes the receiver into a binary form and returns the result.
830+
// To avoid a new allocation the Data slice must have a capacity >= Length + 9
822831
func (p sshFxpDataPacket) MarshalBinary() ([]byte, error) {
823-
b := []byte{sshFxpData}
824-
b = marshalUint32(b, p.ID)
825-
b = marshalUint32(b, p.Length)
826-
b = append(b, p.Data[:p.Length]...)
832+
b := append(p.Data, make([]byte, 9)...)
833+
copy(b[9:], p.Data[:p.Length])
834+
b[0] = sshFxpData
835+
binary.BigEndian.PutUint32(b[1:5], p.ID)
836+
binary.BigEndian.PutUint32(b[5:9], p.Length)
827837
return b, nil
828838
}
829839

request.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,7 @@ func fileget(h FileReader, r *Request, pkt requestPacket) responsePacket {
215215
return statusFromError(pkt, errors.New("unexpected read packet"))
216216
}
217217

218-
_, offset, length := packetData(pkt)
219-
data := make([]byte, clamp(length, maxTxPacket))
218+
data, offset, _ := packetData(pkt)
220219
n, err := reader.ReadAt(data, offset)
221220
// only return EOF erro if no data left to read
222221
if err != nil && (err != io.EOF || n == 0) {
@@ -250,6 +249,7 @@ func packetData(p requestPacket) (data []byte, offset int64, length uint32) {
250249
case *sshFxpReadPacket:
251250
length = p.Len
252251
offset = int64(p.Offset)
252+
data = p.getDataSlice()
253253
case *sshFxpWritePacket:
254254
data = p.Data
255255
length = p.Length

server.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ type Server struct {
3434
openFiles map[string]*os.File
3535
openFilesLock sync.RWMutex
3636
handleCount int
37-
maxTxPacket uint32
3837
}
3938

4039
func (svr *Server) nextHandle(f *os.File) string {
@@ -87,7 +86,6 @@ func NewServer(rwc io.ReadWriteCloser, options ...ServerOption) (*Server, error)
8786
debugStream: ioutil.Discard,
8887
pktMgr: newPktMgr(svrConn),
8988
openFiles: make(map[string]*os.File),
90-
maxTxPacket: 1 << 15,
9189
}
9290

9391
for _, o := range options {
@@ -258,7 +256,7 @@ func handlePacket(s *Server, p orderedRequest) error {
258256
f, ok := s.getHandle(p.Handle)
259257
if ok {
260258
err = nil
261-
data := make([]byte, clamp(p.Len, s.maxTxPacket))
259+
data := p.getDataSlice()
262260
n, _err := f.ReadAt(data, int64(p.Offset))
263261
if _err != nil && (_err != io.EOF || n == 0) {
264262
err = _err
@@ -267,6 +265,7 @@ func handlePacket(s *Server, p orderedRequest) error {
267265
ID: p.ID,
268266
Length: uint32(n),
269267
Data: data[:n],
268+
// do not use data[:n:n] here to clamp the capacity, we allocated extra capacity above to avoid reallocations
270269
}
271270
}
272271
if err != nil {

0 commit comments

Comments
 (0)