Skip to content

Commit

Permalink
opt: improve the conversion between string and byte slice
Browse files Browse the repository at this point in the history
  • Loading branch information
panjf2000 committed Aug 12, 2020
1 parent abbf582 commit 7832a4f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 8 deletions.
47 changes: 47 additions & 0 deletions internal/byteconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2020 Andy Pan
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package internal

import (
"reflect"
"unsafe"
)

// BytesToString converts byte slice to a string without memory allocation.
//
// Note it may break if the implementation of string or slice header changes in the future go versions.
func BytesToString(b []byte) string {
/* #nosec G103 */
return *(*string)(unsafe.Pointer(&b))
}

// StringToBytes converts string to a byte slice without memory allocation.
//
// Note it may break if the implementation of string or slice header changes in the future go versions.
func StringToBytes(s string) (b []byte) {
/* #nosec G103 */
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
/* #nosec G103 */
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))

bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
}
8 changes: 5 additions & 3 deletions load_balancing.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"net"
"sync"
"sync/atomic"

"github.com/panjf2000/gnet/internal"
)

// LoadBalancing represents the the type of load-balancing algorithm.
Expand All @@ -39,7 +41,7 @@ const (
// serving the least number of active connections at the current time.
LeastConnections

// SourceAddrHash assignes the next accepted connection to the event-loop by hashing socket fd.
// SourceAddrHash assignes the next accepted connection to the event-loop by hashing the remote address.
SourceAddrHash
)

Expand Down Expand Up @@ -212,14 +214,14 @@ func (set *sourceAddrHashEventLoopSet) register(el *eventloop) {

// hash hashes a string to a unique hash code.
func (set *sourceAddrHashEventLoopSet) hash(s string) int {
v := int(crc32.ChecksumIEEE([]byte(s)))
v := int(crc32.ChecksumIEEE(internal.StringToBytes(s)))
if v >= 0 {
return v
}
return -v
}

// next returns the eligible event-loop by taking the remainder of a given fd as the index of event-loop list.
// next returns the eligible event-loop by taking the remainder of a hash code as the index of event-loop list.
func (set *sourceAddrHashEventLoopSet) next(netAddr net.Addr) *eventloop {
hashCode := set.hash(netAddr.String())
return set.eventLoops[hashCode%set.size]
Expand Down
6 changes: 1 addition & 5 deletions ringbuffer/ring_buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ package ringbuffer

import (
"errors"
"unsafe"

"github.com/panjf2000/gnet/internal"
"github.com/panjf2000/gnet/pool/bytebuffer"
Expand Down Expand Up @@ -300,10 +299,7 @@ func (r *RingBuffer) Free() int {

// WriteString writes the contents of the string s to buffer, which accepts a slice of bytes.
func (r *RingBuffer) WriteString(s string) (n int, err error) {
x := (*[2]uintptr)(unsafe.Pointer(&s))
h := [3]uintptr{x[0], x[1], x[1]}
buf := *(*[]byte)(unsafe.Pointer(&h))
return r.Write(buf)
return r.Write(internal.StringToBytes(s))
}

// ByteBuffer returns all available read bytes. It does not move the read pointer and only copy the available data.
Expand Down

0 comments on commit 7832a4f

Please sign in to comment.