Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api, core: Add new Core API {Get,Stat}Object with pre-conditions. #670

Merged
merged 1 commit into from
Apr 28, 2017

Conversation

harshavardhana
Copy link
Member

@harshavardhana harshavardhana commented Apr 26, 2017

Implements a new API to provide a way to set headers
for GetObject(), StatObject() request such as to

  • read partial data starting at offsets.
  • read only if etag matches.
  • read only if modtime matches.
  • read only if etag doesn't match.
  • read only if modtime doesn't match.

Fixes #669

// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html
type GetConditions struct {
http.Header
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not:
type PreConditions http.Header

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too generic we already have CopyConditions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But PreConditions are generic header information ... i.e it can apply to HEAD too if required.

SetRange does not sound right for a "Conditions" type.

You could name it just Header

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah you are right.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetRange is appropriate as it is part of the conditions here http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html - Header is not conveying any information.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetRange is under Request Headers section not conditions. i.e Preconditions belongs to Request Headers but Range does not belong to Preconditions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Range also is part of a pre-condition such that you need to validate the requested range first. So i don't agree.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a HTTP point of view you are right Range is not part of Pre-Conditions - https://tools.ietf.org/html/rfc7232#section-3 one needs to set If-Range. But AWS S3 doesn't support that yet.

// Initialize get object conditions and set the appropriate
// range offsets to read from.
conds := GetConditions{}
conds.SetRange(st.Size(), 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will panic as the map is nil

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah will change this.

@harshavardhana harshavardhana force-pushed the get-object branch 3 times, most recently from e4e3603 to 6245b83 Compare April 26, 2017 09:13
// SetRange - set the start and end offset of the object to be read.
// See https://tools.ietf.org/html/rfc7233#section-3.1 for reference.
func (c PreConditions) SetRange(start, end int64) error {
if start < 0 || end > 0 && end < start {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reject when end is negative, it looks it can pass when end = -1 and start = 1 for example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End negative is a valid case.. though.

@@ -0,0 +1,17 @@
package minio
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this file is not needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove.

// Initialize get object conditions and set the appropriate
// range offsets to read from.
conds := NewPreConditions()
conds.SetRange(st.Size(), 0)
Copy link
Member

@vadmeste vadmeste Apr 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be conds.SetRange(0, st.Size()-1)

I understand the meaning of end = 0 now.


// SetRange - set the start and end offset of the object to be read.
// See https://tools.ietf.org/html/rfc7233#section-3.1 for reference.
func (c PreConditions) SetRange(start, end int64) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't download only the first byte with this primitive.

SetRange(0, 0) should be able to return the first byte.

I think end should be -1 when we need to indicate that we want to download from start until the end of the target object.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes there are more cases in pure HTTP, But all cases are not supported by AWS S3.

@harshavardhana harshavardhana force-pushed the get-object branch 7 times, most recently from bad0b1b to e69012b Compare April 26, 2017 19:06
@harshavardhana harshavardhana changed the title api, core: Introduce a new Core API with GetObject pre-conditions. api, core: Add new Core API {Get,Stat}Object with pre-conditions. Apr 26, 2017
@harshavardhana
Copy link
Member Author

Can you check again @krishnasrinivas @vadmeste

case start > 0 && end > 0 && end > start:
// Read everything starting at 'start' till the 'end'. `bytes=N-M`
c.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))
case start == 0 && end == 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the first byte?

I guess S3 can support reading one byte in other positions. You can merge this case with the previous one, so it would be: case start > 0 && end > 0 && end >= start:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

@vadmeste vadmeste left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment

@harshavardhana harshavardhana force-pushed the get-object branch 3 times, most recently from 86bdf05 to a6f206c Compare April 26, 2017 22:34
core_test.go Outdated
io.ReadFull(reader, buf3)
reader.Close()

if objectInfo.Size != int64(len(buf3)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above check doesn't guarantee that len(buf3) bytes were read from reader. The check should be,

n, err = io.ReadFull(reader, buf3)
if err != nil {
  t.Fatal(err)
}

if objectInfo.Size != n {
  t.Fatal(err)
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think that ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number of bytes read would be different than len(buf3) if io.ReadFull returned with io.UnexpectedEOF.

// Initialize get object conditions and set the appropriate
// range offsets to read from.
reqHeaders := NewGetReqHeaders()
reqHeaders.SetRange(st.Size(), 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per, case start > 0 && end == 0: in SetRange(...) method this reqHeaders will request bytes of object starting from st.Size() to EOF, which is not intended. Shouldn't it be SetRange(0, -st.Size())?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@harshavardhana which case statement would match SetRange(st.Size(), 0), where st.Size() > 0?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krisis it looks confusing but st.Size() is actually size of the partially downloaded file, not the size of the object

@harshavardhana harshavardhana force-pushed the get-object branch 3 times, most recently from 982ad47 to 3aa4ee3 Compare April 28, 2017 08:01
Implements a new API to provide a way to set headers
for GetObject(), StatObject() request such as to

 - read partial data starting at offsets.
 - read only if etag matches.
 - read only if modtime matches.
 - read only if etag doesn't match.
 - read only if modtime doesn't match.

Fixes minio#669
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants