Repository: pingcap/tidb
File: pkg/objstore/storeapi/storage.go (Go)

Code before:
	CheckPermissions []Permission

	// S3Retryer is the retryer for create s3 storage, if it is nil,
	// defaultS3Retryer() will be used.
	S3Retryer retry.Standard

	// CheckObjectLockOptions check the s3 bucket has enabled the ObjectLock.
	// if enabled. it will send the options to tikv.
	CheckS3ObjectLockOptions bool
	// AccessRecording records the access statistics of object storage.
	// we use the read/write file size as an estimate of the network traffic,
	// we don't consider the traffic consumed by network protocol, and traffic
	// caused by retry
	AccessRecording *recording.AccessStats
}

// Prefix is like a folder if not empty, we still call it a prefix to match S3
// terminology.
// if not empty, it cannot start with '/' and must end with a '/', such as
// 'a/b/'. the folder name must be valid, we don't check it here.
type Prefix string

// NewPrefix returns a new Prefix instance from the given string.
func NewPrefix(prefix string) Prefix {
	p := strings.Trim(prefix, "/")
	if p != "" && !strings.HasSuffix(p, "/") {
		p += "/"
	}
	return Prefix(p)
}

func (p Prefix) join(other Prefix) Prefix {
	// due to the definition of Prefix, we can add them directly.
	return p + other
}

// JoinStr returns a new Prefix by joining the given string to the current Prefix.
func (p Prefix) JoinStr(str string) Prefix {
	strPrefix := NewPrefix(str)
	return p.join(strPrefix)
}

// ObjectKey returns the object key by joining the name to the Prefix.
func (p Prefix) ObjectKey(name string) string {
	// if p is not empty, it already ends with '/'.
	// the name better not start with '/', else there will be double '/' in the
	// key.
	// this is existing behavior, we keep it.
	return string(p) + name
}


Review comment (refactor):
The condition `!strings.HasSuffix(p, "/")` on line 212 is redundant. After `strings.Trim(prefix, "/")` on line 211, the string p can never have a suffix of "/" (trim removes all leading and trailing "/" characters). The condition will always be true when p is non-empty. Consider simplifying to just check if p is non-empty.
```suggestion
	if p != "" {
```

Code after:
	CheckPermissions []Permission

	// S3Retryer is the retryer for create s3 storage, if it is nil,
	// defaultS3Retryer() will be used.
	S3Retryer retry.Standard

	// CheckObjectLockOptions check the s3 bucket has enabled the ObjectLock.
	// if enabled. it will send the options to tikv.
	CheckS3ObjectLockOptions bool
	// AccessRecording records the access statistics of object storage.
	// we use the read/write file size as an estimate of the network traffic,
	// we don't consider the traffic consumed by network protocol, and traffic
	// caused by retry
	AccessRecording *recording.AccessStats
}

// Prefix is like a folder if not empty, we still call it a prefix to match S3
// terminology.
// if not empty, it cannot start with '/' and must end with a '/', such as
// 'a/b/'. the folder name must be valid, we don't check it here.
type Prefix string

// NewPrefix returns a new Prefix instance from the given string.
func NewPrefix(prefix string) Prefix {
	p := strings.Trim(prefix, "/")
	if p != "" {
		p += "/"
	}
	return Prefix(p)
}

func (p Prefix) join(other Prefix) Prefix {
	// due to the definition of Prefix, we can add them directly.
	return p + other
}

// JoinStr returns a new Prefix by joining the given string to the current Prefix.
func (p Prefix) JoinStr(str string) Prefix {
	strPrefix := NewPrefix(str)
	return p.join(strPrefix)
}

// ObjectKey returns the object key by joining the name to the Prefix.
func (p Prefix) ObjectKey(name string) string {
	// if p is not empty, it already ends with '/'.
	// the name better not start with '/', else there will be double '/' in the
	// key.
	// this is existing behavior, we keep it.
	return string(p) + name
}