Skip to content

Commit

Permalink
micro-optimize obj props to http headers conversion
Browse files Browse the repository at this point in the history
* target obj-head handler: use pre-mapped headers, avoid repetitive churn
* api/apc: fuse textproto logic; optimize and simplify
* part two, prev. commit: 530288d

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Sep 3, 2024
1 parent d686c59 commit 212d2f7
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 18 deletions.
6 changes: 1 addition & 5 deletions ais/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
36 changes: 32 additions & 4 deletions api/apc/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package apc

import (
"strings"
"unicode"

"github.com/NVIDIA/aistore/cmn/cos"
"github.com/NVIDIA/aistore/cmn/debug"
)

Expand Down Expand Up @@ -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)
}
6 changes: 2 additions & 4 deletions api/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"io"
"net/http"
"net/textproto"
"net/url"
"strconv"
"time"
Expand Down Expand Up @@ -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
}
Expand Down
7 changes: 2 additions & 5 deletions cmn/objattrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package cmn
import (
"fmt"
"net/http"
"net/textproto"
"strconv"
"strings"

Expand Down Expand Up @@ -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})

Expand Down

0 comments on commit 212d2f7

Please sign in to comment.