From a1bebf827447a9d6c14851770da231f9b270e22d Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Fri, 1 Dec 2023 16:45:17 -0500 Subject: [PATCH] Avoid unnecessary reopening of HTTP streams in GetObject() Sometimes consumers of Seek() might use it for purposes other than chaging the current read/write offset. For example, using whence = io.SeekCurrent to get the current seek position. However, minio-go invalidates the underlying HTTP stream unconditionally when Seek() is called, resulting in massive performance degradation in these scenarios. This commit avoids these issues by only reopening the stream if the seek position is actually changed. --- api-get-object.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/api-get-object.go b/api-get-object.go index e31e4cf929..9e6b1543c4 100644 --- a/api-get-object.go +++ b/api-get-object.go @@ -550,6 +550,8 @@ func (o *Object) Seek(offset int64, whence int) (n int64, err error) { } } + newOffset := o.currOffset + // Switch through whence. switch whence { default: @@ -558,12 +560,12 @@ func (o *Object) Seek(offset int64, whence int) (n int64, err error) { if o.objectInfo.Size > -1 && offset > o.objectInfo.Size { return 0, io.EOF } - o.currOffset = offset + newOffset = offset case 1: if o.objectInfo.Size > -1 && o.currOffset+offset > o.objectInfo.Size { return 0, io.EOF } - o.currOffset += offset + newOffset += offset case 2: // If we don't know the object size return an error for io.SeekEnd if o.objectInfo.Size < 0 { @@ -579,7 +581,7 @@ func (o *Object) Seek(offset int64, whence int) (n int64, err error) { if o.objectInfo.Size+offset < 0 { return 0, errInvalidArgument(fmt.Sprintf("Seeking at negative offset not allowed for %d", whence)) } - o.currOffset = o.objectInfo.Size + offset + newOffset = o.objectInfo.Size + offset } // Reset the saved error since we successfully seeked, let the Read // and ReadAt decide. @@ -587,8 +589,9 @@ func (o *Object) Seek(offset int64, whence int) (n int64, err error) { o.prevErr = nil } - // Ask lower level to fetch again from source - o.seekData = true + // Ask lower level to fetch again from source when necessary + o.seekData = (newOffset != o.currOffset) || o.seekData + o.currOffset = newOffset // Return the effective offset. return o.currOffset, nil