Optimize packWithCompression

This commit is contained in:
Tnze
2023-04-05 22:24:46 +08:00
parent 943d9fbe26
commit e99e749f7f

View File

@ -8,7 +8,7 @@ import (
"sync" "sync"
) )
const MaxDataLength = 2097152 const MaxDataLength = 0x200000
// Packet define a net data package // Packet define a net data package
type Packet struct { type Packet struct {
@ -37,11 +37,10 @@ func (p Packet) Scan(fields ...FieldDecoder) error {
return nil return nil
} }
var bufPool = sync.Pool{ var (
New: func() any { bufPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}
return new(bytes.Buffer) zlibPool = sync.Pool{New: func() any { return zlib.NewWriter(io.Discard) }}
}, )
}
// Pack 打包一个数据包 // Pack 打包一个数据包
func (p *Packet) Pack(w io.Writer, threshold int) error { func (p *Packet) Pack(w io.Writer, threshold int) error {
@ -55,63 +54,65 @@ func (p *Packet) Pack(w io.Writer, threshold int) error {
func (p *Packet) packWithoutCompression(w io.Writer) error { func (p *Packet) packWithoutCompression(w io.Writer) error {
buffer := bufPool.Get().(*bytes.Buffer) buffer := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buffer) defer bufPool.Put(buffer)
// Pre-allocate room at the front of the packet for the length field
buffer.Reset() buffer.Reset()
buffer.Write([]byte{0, 0, 0})
VarInt(p.ID).WriteTo(buffer) // Write Length to buffer
Length := VarInt(VarInt(p.ID).Len() + len(p.Data))
_, _ = Length.WriteTo(buffer)
// Write ID and Data to buffer
_, _ = VarInt(p.ID).WriteTo(buffer)
buffer.Write(p.Data) buffer.Write(p.Data)
// Write length at front // Write buffer to w
payloadLen := VarInt(buffer.Len() - 3) _, err := w.Write(buffer.Bytes())
varIntOffset := 3 - payloadLen.Len()
payloadLen.WriteToBytes(buffer.Bytes()[varIntOffset:])
_, err := w.Write(buffer.Bytes()[varIntOffset:])
return err return err
} }
func (p *Packet) packWithCompression(w io.Writer, threshold int) error { func (p *Packet) packWithCompression(w io.Writer, threshold int) error {
buff := bufPool.Get().(*bytes.Buffer) buff := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buff) defer bufPool.Put(buff)
// Allocate room for the 'packet length' and 'data length' fields. Each can take up to 3 bytes
buff.Reset() buff.Reset()
buff.Write([]byte{0, 0, 0, 0, 0, 0})
var writeStart int
PacketID := VarInt(p.ID)
if len(p.Data) < threshold { if len(p.Data) < threshold {
VarInt(p.ID).WriteTo(buff) DataLength := VarInt(0) // uncompressed mark
buff.Write(p.Data) PacketLength := VarInt(DataLength.Len() + PacketID.Len() + len(p.Data))
// Packet is below compression threshold so 'data length' is 0 _, _ = PacketLength.WriteTo(buff)
// Front of the packet is already initialized to 0, so just decrement the offset _, _ = DataLength.WriteTo(buff)
writeStart = 5 _, _ = PacketID.WriteTo(buff)
_, _ = buff.Write(p.Data)
} else { } else {
zw := zlib.NewWriter(buff) DataLength := VarInt(PacketID.Len() + len(p.Data))
varIntLen, _ := VarInt(p.ID).WriteTo(zw)
zw.Write(p.Data)
err := zw.Close() buff.Write(make([]byte, MaxVarIntLen)) // padding for Packet Length
if err != nil { _, _ = DataLength.WriteTo(buff)
if err := compressPacket(buff, p.ID, p.Data); err != nil {
return err return err
} }
// Write 'data length' before ID + payload PacketLength := VarInt(buff.Len() - MaxVarIntLen)
uncompressedLen := VarInt(varIntLen + int64(len(p.Data))) packetLengthLen := PacketLength.Len()
writeStart = 6 - uncompressedLen.Len() buff.Next(MaxVarIntLen - packetLengthLen)
uncompressedLen.WriteToBytes(buff.Bytes()[writeStart:]) PacketLength.WriteToBytes(buff.Bytes()[:packetLengthLen])
} }
// Write 'packet length' before all other fields _, err := w.Write(buff.Bytes())
packetLen := VarInt(buff.Len() - writeStart)
start := writeStart - packetLen.Len()
VarInt(packetLen).WriteToBytes(buff.Bytes()[start:])
_, err := w.Write(buff.Bytes()[start:])
return err return err
} }
func compressPacket(w io.Writer, PacketID int32, Data []byte) error {
zw := zlibPool.Get().(*zlib.Writer)
defer zlibPool.Put(zw)
zw.Reset(w)
_, _ = VarInt(PacketID).WriteTo(zw)
if _, err := zw.Write(Data); err != nil {
return err
}
return zw.Close()
}
// UnPack in-place decompression a packet // UnPack in-place decompression a packet
func (p *Packet) UnPack(r io.Reader, threshold int) error { func (p *Packet) UnPack(r io.Reader, threshold int) error {
if threshold >= 0 { if threshold >= 0 {