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

Code before:

// NewBucketPrefix returns a new BucketPrefix instance.
func NewBucketPrefix(bucket, prefix string) BucketPrefix {
	return BucketPrefix{
		Bucket: bucket,
		Prefix: NewPrefix(prefix),
	}
}

// ObjectKey returns the object key by joining the name to the Prefix.
func (bp *BucketPrefix) ObjectKey(name string) string {
	return bp.Prefix.ObjectKey(name)
}

// PrefixStr returns the Prefix as a string.
func (bp *BucketPrefix) PrefixStr() string {
	return bp.Prefix.String()
}

// GetHTTPRange returns the HTTP Range header value for the given start and end
// offsets.
// if endOffset is not 0, startOffset must <= endOffset, we don't check the
// validity here.
// if startOffset = 0, `full` = true and 'rangeVal' is empty, else a partial
// object is requested, `full` is false and `rangeVal` contains the Range header
// value.
func GetHTTPRange(startOffset, endOffset int64) (full bool, rangeVal string) {
	// If we just open part of the object, we set `Range` in the request.
	// If we meant to open the whole object, not just a part of it,
	// we do not pass the range in the request,
	// so that even if the object is empty, we can still get the response without errors.
	// Then this behavior is similar to opening an empty file in local file system.
	switch {
	case endOffset > startOffset:
		// both end of http Range header are inclusive
		rangeVal = fmt.Sprintf("bytes=%d-%d", startOffset, endOffset-1)
	case startOffset == 0:
		// opening the whole object, no need to fill the `Range` field in the request
		full = true
	default:
		rangeVal = fmt.Sprintf("bytes=%d-", startOffset)
	}
	return
}


Review comment (suggestion):
The documentation comment has an inconsistency. It states "if startOffset = 0, `full` = true", but this is only true when both startOffset and endOffset are 0. When startOffset is 0 but endOffset is greater than 0, the function returns full=false with a range value. The documentation should clarify that full=true only when both startOffset and endOffset are 0 (case startOffset == 0 && endOffset == 0).
```suggestion
// If endOffset is not 0, startOffset must <= endOffset; we don't check the
// validity here.
// If startOffset == 0 and endOffset == 0, `full` is true and `rangeVal` is empty.
// Otherwise a partial object is requested, `full` is false and `rangeVal` contains
// the Range header value.
```

Code after:

// NewBucketPrefix returns a new BucketPrefix instance.
func NewBucketPrefix(bucket, prefix string) BucketPrefix {
	return BucketPrefix{
		Bucket: bucket,
		Prefix: NewPrefix(prefix),
	}
}

// ObjectKey returns the object key by joining the name to the Prefix.
func (bp *BucketPrefix) ObjectKey(name string) string {
	return bp.Prefix.ObjectKey(name)
}

// PrefixStr returns the Prefix as a string.
func (bp *BucketPrefix) PrefixStr() string {
	return bp.Prefix.String()
}

// GetHTTPRange returns the HTTP Range header value for the given start and end
// offsets.
// If endOffset is not 0, startOffset must <= endOffset; we don't check the
// validity here.
// If startOffset == 0 and endOffset == 0, `full` is true and `rangeVal` is empty.
// Otherwise, a partial object is requested, `full` is false and `rangeVal`
// contains the Range header value.
func GetHTTPRange(startOffset, endOffset int64) (full bool, rangeVal string) {
	// If we just open part of the object, we set `Range` in the request.
	// If we meant to open the whole object, not just a part of it,
	// we do not pass the range in the request,
	// so that even if the object is empty, we can still get the response without errors.
	// Then this behavior is similar to opening an empty file in local file system.
	switch {
	case endOffset > startOffset:
		// both end of http Range header are inclusive
		rangeVal = fmt.Sprintf("bytes=%d-%d", startOffset, endOffset-1)
	case startOffset == 0:
		// opening the whole object, no need to fill the `Range` field in the request
		full = true
	default:
		rangeVal = fmt.Sprintf("bytes=%d-", startOffset)
	}
	return
}