summaryrefslogtreecommitdiff
path: root/proto/io.go
diff options
context:
space:
mode:
Diffstat (limited to 'proto/io.go')
-rw-r--r--proto/io.go57
1 files changed, 54 insertions, 3 deletions
diff --git a/proto/io.go b/proto/io.go
index 34421b1..0f231c8 100644
--- a/proto/io.go
+++ b/proto/io.go
@@ -23,6 +23,7 @@ import (
"io"
"net"
"reflect"
+ "sync"
"syscall"
)
@@ -41,6 +42,7 @@ type nslcdObjectPtr interface {
}
type String []byte
+
func (s String) String() string {
return string(s)
}
@@ -54,7 +56,7 @@ func (data String) nslcdWrite(fd io.Writer) {
func (data *String) nslcdRead(fd io.Reader) {
var len int32
Read(fd, &len)
- buf := make([]byte, len)
+ buf := makeBytes(len)
Read(fd, &buf)
*data = String(buf)
}
@@ -94,7 +96,7 @@ func Write(fd io.Writer, data interface{}) {
}
var bytes []byte
if af < 0 {
- bytes = make([]byte, 0)
+ bytes = makeBytes(0)
} else {
bytes = data
}
@@ -163,7 +165,7 @@ func Read(fd io.Reader, data interface{}) {
if len != _len {
panic(NslcdError(fmt.Sprintf("address length incorrect: %d", len)))
}
- buf := make([]byte, len)
+ buf := makeBytes(len)
Read(fd, &buf)
*data = buf
case *[]net.IP:
@@ -184,3 +186,52 @@ func Read(fd io.Reader, data interface{}) {
}
}
}
+
+// "Free" an object and its members, returning them to various pools.
+// This keeps the GC sane.
+func Free(data interface{}) {
+ switch data := data.(type) {
+ case *[]byte:
+ bytePool.Put(*data)
+ case *int32:
+ // do nothing
+ case *String:
+ bytes := []byte(*data)
+ bytePool.Put(bytes)
+ case *[]String:
+ for _, str := range *data {
+ Free(&str)
+ }
+ case *net.IP:
+ bytes := []byte(*data)
+ bytePool.Put(bytes)
+ case *[]net.IP:
+ for _, ip := range *data {
+ Free(&ip)
+ }
+ default:
+ p := reflect.ValueOf(data)
+ v := reflect.Indirect(p)
+ if p == v || v.Kind() != reflect.Struct {
+ panic(fmt.Sprintf("The argument to nslcd_proto.Free() must be a pointer: %T ( %#v )", data, data))
+ }
+ for i, n := 0, v.NumField(); i < n; i++ {
+ Free(v.Field(i).Addr().Interface())
+ }
+ }
+}
+
+var bytePool = sync.Pool{
+ New: func() interface{} {
+ return make([]byte, 0, 256)
+ },
+}
+
+func makeBytes(l int32) []byte {
+ buf := bytePool.Get().([]byte)
+ if cap(buf) < int(l) {
+ bytePool.Put(buf)
+ buf = make([]byte, l)
+ }
+ return buf[:l]
+}