From 17ab1c238f513f8a0253cdc460ec5e52292cf818 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 14 Aug 2014 12:59:54 -0700 Subject: [PATCH] Change strutil.StringFromBytes to depend on Go 1.3. Change-Id: I83fd1369a199dba7ef41227df4d0b95d9a16aabb --- pkg/schema/schema.go | 16 ++++++++++++++ pkg/strutil/intern.go | 49 +++++++++++++++---------------------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index b0f38162f..46ef97c32 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -41,12 +41,28 @@ import ( "unicode/utf8" "camlistore.org/pkg/blob" + "camlistore.org/pkg/strutil" "camlistore.org/pkg/types" "camlistore.org/third_party/github.com/bradfitz/latlong" "camlistore.org/third_party/github.com/camlistore/goexif/exif" "camlistore.org/third_party/github.com/camlistore/goexif/tiff" ) +func init() { + // Intern common strings as used by schema blobs (camliType values), to reduce + // index memory usage, which uses strutil.StringFromBytes. + strutil.RegisterCommonString( + "bytes", + "claim", + "directory", + "file", + "permanode", + "share", + "static-set", + "symlink", + ) +} + // MaxSchemaBlobSize represents the upper bound for how large // a schema blob may be. const MaxSchemaBlobSize = 1 << 20 diff --git a/pkg/strutil/intern.go b/pkg/strutil/intern.go index 01bb05106..633ebb361 100644 --- a/pkg/strutil/intern.go +++ b/pkg/strutil/intern.go @@ -16,39 +16,24 @@ limitations under the License. package strutil -// StringFromBytes returns string(v), minimizing copies for common values of v. +var internStr = map[string]string{} + +// RegisterCommonString adds common strings to the interned string +// table. This should be called during init from the main +// goroutine, not later at runtime. +func RegisterCommonString(s ...string) { + for _, v := range s { + internStr[v] = v + } +} + +// StringFromBytes returns string(v), minimizing copies for common values of v +// as previously registered with RegisterCommonString. func StringFromBytes(v []byte) string { - // From net/textproto's reader.go... - if len(v) == 0 { - return "" - } - lo, hi := 0, len(commonStrings) - for i, c := range v { - if lo < hi { - for lo < hi && (len(commonStrings[lo]) <= i || commonStrings[lo][i] < c) { - lo++ - } - for hi > lo && commonStrings[hi-1][i] > c { - hi-- - } - } else { - break - } - } - if lo < hi && len(commonStrings[lo]) == len(v) { - return commonStrings[lo] + // In Go 1.3, this string conversion in the map lookup does not allocate + // to make a new string. We depend on Go 1.3, so this is always free: + if s, ok := internStr[string(v)]; ok { + return s } return string(v) } - -// NOTE: must be sorted -var commonStrings = []string{ - "bytes", - "claim", - "directory", - "file", - "permanode", - "share", - "static-set", - "symlink", -}