Skip to content

Commit

Permalink
micro-optimize obj props to http headers conversion
Browse files Browse the repository at this point in the history
1. canonicalize all header constants
2. add static map: [internal prop name => canonical header name]

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Sep 3, 2024
1 parent 7530930 commit 530288d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 58 deletions.
2 changes: 2 additions & 0 deletions ais/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ func initDaemon(version, buildTime string) cos.Runner {
nlog.SetTitle(title)
cmn.InitErrs(t.si.Name(), fs.CleanPathErr)

cmn.InitObjProps2Hdr()

return t
}

Expand Down
105 changes: 52 additions & 53 deletions api/apc/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
*/
package apc

import "strings"
import (
"strings"

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

// AIS http header conventions:
// - always starts with the prefix "ais-"
Expand All @@ -15,61 +19,61 @@ import "strings"
const HdrError = "Hdr-Error"

const (
HeaderPrefix = "ais-"
aisPrefix = "Ais-"

// bucket inventory - an alternative way to list (very large) buckets
HdrInventory = HeaderPrefix + "bucket-inventory" // must be present and must be "true" (or "y", "yes", "on" case-insensitive)
HdrInvName = HeaderPrefix + "inv-name" // optional; name of the inventory (to override the system default)
HdrInvID = HeaderPrefix + "inv-id" // optional; inventory ID (ditto)
HdrInventory = aisPrefix + "Bucket-Inventory" // must be present and must be "true" (or "y", "yes", "on" case-insensitive)
HdrInvName = aisPrefix + "Inv-Name" // optional; name of the inventory (to override the system default)
HdrInvID = aisPrefix + "Inv-Id" // optional; inventory ID (ditto)

// GET via x-blob-download
HdrBlobDownload = HeaderPrefix + ActBlobDl // must be present and must be "true" (or "y", "yes", "on" case-insensitive)
HdrBlobChunk = HeaderPrefix + "blob-chunk" // optional; e.g., 1mb, 2MIB, 3m, or 1234567 (bytes)
HdrBlobWorkers = HeaderPrefix + "blob-workers" // optional; the default number of workers is dfltNumWorkers in xs/blob_download.go
HdrBlobDownload = aisPrefix + "Blob-Download" // must be present and must be "true" (or "y", "yes", "on" case-insensitive)
HdrBlobChunk = aisPrefix + "Blob-Chunk" // optional; e.g., 1mb, 2MIB, 3m, or 1234567 (bytes)
HdrBlobWorkers = aisPrefix + "Blob-Workers" // optional; the default number of workers is dfltNumWorkers in xs/blob_download.go

// Bucket props headers
HdrBucketProps = HeaderPrefix + "bucket-props" // => cmn.Bprops
HdrBucketSumm = HeaderPrefix + "bucket-summ" // => cmn.BsummResult (see also: QparamFltPresence)
HdrBucketVerEnabled = HeaderPrefix + "versioning-enabled" // Enable/disable object versioning in a bucket.
HdrBackendProvider = HeaderPrefix + "provider" // ProviderAmazon et al. - see cmn/bck.go.
HdrBucketProps = aisPrefix + "Bucket-Props" // => cmn.Bprops
HdrBucketSumm = aisPrefix + "Bucket-Summ" // => cmn.BsummResult (see also: QparamFltPresence)
HdrBucketVerEnabled = aisPrefix + "Versioning-Enabled" // Enable/disable object versioning in a bucket.
HdrBackendProvider = aisPrefix + "Provider" // ProviderAmazon et al. - see cmn/bck.go.

// including BucketProps.Extra.AWS
HdrS3Region = HeaderPrefix + "cloud_region"
HdrS3Endpoint = HeaderPrefix + "endpoint"
HdrS3Profile = HeaderPrefix + "profile"
HdrS3Region = aisPrefix + "Cloud_region"
HdrS3Endpoint = aisPrefix + "Endpoint"
HdrS3Profile = aisPrefix + "Profile"

// including BucketProps.Extra.HTTP
HdrOrigURLBck = HeaderPrefix + "original-url"
HdrOrigURLBck = aisPrefix + "Original-Url"

// remote AIS
HdrRemAisUUID = HeaderPrefix + "remote-ais-uuid"
HdrRemAisAlias = HeaderPrefix + "remote-ais-alias"
HdrRemAisURL = HeaderPrefix + "remote-ais-url"
HdrRemAisUUID = aisPrefix + "Remote-Ais-Uuid"
HdrRemAisAlias = aisPrefix + "Remote-Ais-Alias"
HdrRemAisURL = aisPrefix + "Remote-Ais-Url"

HdrRemoteOffline = HeaderPrefix + "remote-offline" // When accessing cached remote bucket with no backend connectivity.
HdrRemoteOffline = aisPrefix + "Remote-Offline" // When accessing cached remote bucket with no backend connectivity.

// Object props headers
HdrObjCksumType = HeaderPrefix + "checksum-type" // Checksum type, one of SupportedChecksums().
HdrObjCksumVal = HeaderPrefix + "checksum-value" // Checksum value.
HdrObjAtime = HeaderPrefix + "atime" // Object access time.
HdrObjCustomMD = HeaderPrefix + "custom-md" // Object custom metadata.
HdrObjVersion = HeaderPrefix + "version" // Object version/generation - ais or cloud.
HdrObjCksumType = aisPrefix + "Checksum-Type" // Checksum type, one of SupportedChecksums().
HdrObjCksumVal = aisPrefix + "Checksum-Value" // Checksum value.
HdrObjAtime = aisPrefix + "Atime" // Object access time.
HdrObjCustomMD = aisPrefix + "Custom-Md" // Object custom metadata.
HdrObjVersion = aisPrefix + "Version" // Object version/generation - ais or cloud.

// Append object header.
HdrAppendHandle = HeaderPrefix + "append-handle"
// Append object header
HdrAppendHandle = aisPrefix + "Append-Handle"

// api.PutApndArchArgs message flags
HdrPutApndArchFlags = HeaderPrefix + "pine"
HdrPutApndArchFlags = aisPrefix + "Pine"

// Query objects handle header.
HdrHandle = HeaderPrefix + "query-handle"
// Query objects handle header
HdrHandle = aisPrefix + "Query-Handle"

// Reverse proxy header.
HdrNodeID = HeaderPrefix + "node-id"
// Reverse proxy header
HdrNodeID = aisPrefix + "Node-Id"

// uptimes, respectively
HdrNodeUptime = HeaderPrefix + "node-uptime"
HdrClusterUptime = HeaderPrefix + "cluster-uptime"
HdrNodeUptime = aisPrefix + "Node-Uptime"
HdrClusterUptime = aisPrefix + "Cluster-Uptime"
)

// AuthN consts
Expand All @@ -80,35 +84,30 @@ const (

// Internally used headers
const (
HdrCallerID = HeaderPrefix + "caller-id" // Marker of intra-cluster request.
HdrT2TPutterID = HeaderPrefix + "putter-id" // DaemonID of the target that performs intra-cluster PUT
HdrCallerName = HeaderPrefix + "caller-name"
HdrCallerIsPrimary = HeaderPrefix + "caller-is-primary"
HdrCallerSmapVer = HeaderPrefix + "caller-smap-ver"
HdrCallerID = aisPrefix + "Caller-Id" // Marker of intra-cluster request.
HdrT2TPutterID = aisPrefix + "Putter-Id" // DaemonID of the target that performs intra-cluster PUT
HdrCallerName = aisPrefix + "Caller-Name"
HdrCallerIsPrimary = aisPrefix + "Caller-Is-Primary"
HdrCallerSmapVer = aisPrefix + "Caller-Smap-Ver"

HdrXactionID = HeaderPrefix + "xaction-id"
HdrXactionID = aisPrefix + "Xaction-Id"

// Stream related headers.
HdrSessID = HeaderPrefix + "session-id"
HdrCompress = HeaderPrefix + "compress" // LZ4Compression, etc.
// intra-cluster streams
HdrSessID = aisPrefix + "Session-Id"
HdrCompress = aisPrefix + "Compress" // LZ4

// Promote(dir)
HdrPromoteNamesHash = HeaderPrefix + "promote-names-hash"
HdrPromoteNamesNum = HeaderPrefix + "promote-names-num"
HdrPromoteNamesHash = aisPrefix + "Promote-Names-Hash"
HdrPromoteNamesNum = aisPrefix + "Promote-Names-Num"
)

//
// convert prop name to HTTP header tag name
//

// (compare with cmn.PropToHeader)
func PropToHeader(prop string) string {
if strings.HasPrefix(prop, HeaderPrefix) {
return prop
}
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 HeaderPrefix + prop
return aisPrefix + prop
}
12 changes: 7 additions & 5 deletions api/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,20 +347,22 @@ func HeadObject(bp BaseParams, bck cmn.Bck, objName string, args HeadArgs) (*cmn
return nil, err
}

// first, cnm.ObjAttrs (NOTE: compare with `headObject()` in target.go)
// first, cnm.ObjAttrs (compare with `t.objHead`)
op := &cmn.ObjectProps{}
op.Cksum = op.ObjAttrs.FromHeader(hdr)

// second, all the rest
err = cmn.IterFields(op, func(tag string, field cmn.IterField) (error, bool) {
headerName := apc.PropToHeader(tag)
// get values, skip the missing ones
v, ok := hdr[textproto.CanonicalMIMEHeaderKey(headerName)]
h1 := apc.PropToHeader(tag)
h2 := textproto.CanonicalMIMEHeaderKey(h1)
v, ok := hdr[h2]
if !ok {
return nil, false
return nil, false // skip missing
}
// single-value
return field.SetValue(v[0], true /*force*/), false
}, cmn.IterOpts{OnlyRead: false})

if err != nil {
return nil, err
}
Expand Down
28 changes: 28 additions & 0 deletions cmn/objattrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package cmn
import (
"fmt"
"net/http"
"net/textproto"
"strconv"
"strings"

Expand Down Expand Up @@ -72,6 +73,33 @@ type ObjAttrs struct {
// interface guard
var _ cos.OAH = (*ObjAttrs)(nil)

// static map: [internal (json) obj prop => canonical http header]
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
return nil, false
}, IterOpts{OnlyRead: false})

debug.Assert(err == nil && len(props2hdr) <= 18, "err: ", err, " len: ", len(props2hdr))
}

// (compare with apc.PropToHeader)
func PropToHeader(prop string) string {
headerName, ok := props2hdr[prop]
debug.Assert(ok, "unknown obj prop: ", prop) // NOTE: assuming, InitObjProps2Hdr captures all statically
return headerName
}

func (oa *ObjAttrs) String() string {
return fmt.Sprintf("%dB, v%q, %s, %+v", oa.Size, oa.Version(), oa.Cksum, oa.CustomMD)
}
Expand Down

0 comments on commit 530288d

Please sign in to comment.