diff --git a/ais/daemon.go b/ais/daemon.go index 7918b1b670..86809f9298 100644 --- a/ais/daemon.go +++ b/ais/daemon.go @@ -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 } diff --git a/api/apc/headers.go b/api/apc/headers.go index 8e018c649d..5174881b06 100644 --- a/api/apc/headers.go +++ b/api/apc/headers.go @@ -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-" @@ -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 @@ -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 } diff --git a/api/object.go b/api/object.go index ca85f6a061..84b9fe23be 100644 --- a/api/object.go +++ b/api/object.go @@ -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 } diff --git a/cmn/objattrs.go b/cmn/objattrs.go index 6ec7935cd0..235fb0cdb2 100644 --- a/cmn/objattrs.go +++ b/cmn/objattrs.go @@ -8,6 +8,7 @@ package cmn import ( "fmt" "net/http" + "net/textproto" "strconv" "strings" @@ -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) }