From 212d2f72f9297a092b3a1955f737cbf33fe94cf3 Mon Sep 17 00:00:00 2001 From: Alex Aizman Date: Tue, 3 Sep 2024 15:05:09 -0400 Subject: [PATCH] micro-optimize obj props to http headers conversion * target obj-head handler: use pre-mapped headers, avoid repetitive churn * api/apc: fuse textproto logic; optimize and simplify * part two, prev. commit: 530288d44fa5fe26 Signed-off-by: Alex Aizman --- ais/target.go | 6 +----- api/apc/headers.go | 36 ++++++++++++++++++++++++++++++++---- api/object.go | 6 ++---- cmn/objattrs.go | 7 ++----- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/ais/target.go b/ais/target.go index ff8455af2b..5d51b8e609 100644 --- a/ais/target.go +++ b/ais/target.go @@ -1157,11 +1157,7 @@ func (t *target) objHead(r *http.Request, whdr http.Header, q url.Values, bck *m if v == "" { return nil, false } - name := apc.PropToHeader(tag) - debug.Func(func() { - vv := whdr.Get(name) - debug.Assertf(vv == "", "not expecting duplications: %s=(%q, %q)", name, v, vv) - }) + name := cmn.PropToHeader(tag) whdr.Set(name, v) return nil, false }) diff --git a/api/apc/headers.go b/api/apc/headers.go index 5174881b06..676dc541f2 100644 --- a/api/apc/headers.go +++ b/api/apc/headers.go @@ -6,7 +6,9 @@ package apc import ( "strings" + "unicode" + "github.com/NVIDIA/aistore/cmn/cos" "github.com/NVIDIA/aistore/cmn/debug" ) @@ -101,13 +103,39 @@ const ( HdrPromoteNamesNum = aisPrefix + "Promote-Names-Num" ) -// (compare with cmn.PropToHeader) +const lais = len(aisPrefix) + +// internal (json) obj prop => canonical http header +// usage: +// - target InitObjProps2Hdr +// - api/object func PropToHeader(prop string) string { debug.Assert(!strings.HasPrefix(prop, aisPrefix), "already converted: ", prop) if prop[0] == '.' || prop[0] == '_' { prop = prop[1:] } - prop = strings.ReplaceAll(prop, ".", "-") - prop = strings.ReplaceAll(prop, "_", "-") - return aisPrefix + prop + + var ( + l = len(prop) + out = make([]byte, l+lais) + o = out[lais:] + up = true + ) + copy(out, aisPrefix) + for i := range l { + c := prop[i] + if c == '.' || c == '_' { + c = '-' + } + switch { + case up && 'a' <= c && c <= 'z': + o[i] = byte(unicode.ToUpper(rune(c))) + case !up && 'A' <= c && c <= 'Z': + o[i] = byte(unicode.ToLower(rune(c))) + default: + o[i] = c + } + up = c == '-' + } + return cos.UnsafeS(out) } diff --git a/api/object.go b/api/object.go index 84b9fe23be..11c598342c 100644 --- a/api/object.go +++ b/api/object.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "net/http" - "net/textproto" "net/url" "strconv" "time" @@ -353,9 +352,8 @@ func HeadObject(bp BaseParams, bck cmn.Bck, objName string, args HeadArgs) (*cmn // second, all the rest err = cmn.IterFields(op, func(tag string, field cmn.IterField) (error, bool) { - h1 := apc.PropToHeader(tag) - h2 := textproto.CanonicalMIMEHeaderKey(h1) - v, ok := hdr[h2] + name := apc.PropToHeader(tag) // internal (json) obj prop => canonical http header + v, ok := hdr[name] if !ok { return nil, false // skip missing } diff --git a/cmn/objattrs.go b/cmn/objattrs.go index 235fb0cdb2..6a8ee3faf1 100644 --- a/cmn/objattrs.go +++ b/cmn/objattrs.go @@ -8,7 +8,6 @@ package cmn import ( "fmt" "net/http" - "net/textproto" "strconv" "strings" @@ -78,15 +77,13 @@ var ( props2hdr cos.StrKVs ) -// (compare with api.HeadObject) func InitObjProps2Hdr() { props2hdr = make(cos.StrKVs, 18) op := &ObjectProps{} err := IterFields(op, func(tag string, _ IterField) (error, bool) { - h1 := apc.PropToHeader(tag) - h2 := textproto.CanonicalMIMEHeaderKey(h1) - props2hdr[tag] = h2 + name := apc.PropToHeader(tag) + props2hdr[tag] = name // internal (json) obj prop => canonical http header return nil, false }, IterOpts{OnlyRead: false})