From 7c8e5d6737fb69816401e3918d838d20183177cf Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Fri, 1 Dec 2023 17:03:26 -0500 Subject: [PATCH] Avoid unnecessary reopening of HTTP streams in GetObject() (#1908) 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 e31e4cf92..9e6b1543c 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