diff options
Diffstat (limited to 'proto/io.go')
-rw-r--r-- | proto/io.go | 57 |
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] +} |