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

Lock free multipart backend implementation for FS #5401

Merged
merged 1 commit into from Jan 31, 2018

Conversation

krishnasrinivas
Copy link
Contributor

@krishnasrinivas krishnasrinivas commented Jan 15, 2018

Description

https://github.com/krishnasrinivas/wikinotes/wiki/FS-multipart-backend

Motivation and Context

Implement lock free multipart backend.

How Has This Been Tested?

manual.
unit tests fail. Looking into it

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added unit tests to cover my changes.
  • I have added/updated functional tests in mint. (If yes, add mint PR # here: )
  • All new and existing tests passed.

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 2 times, most recently from dfaa4f5 to 7762002 Compare January 16, 2018 01:27
@harshavardhana
Copy link
Member

Is this still a WIP @krishnasrinivas can you fix the CI failures?

)

var DefaultBufferSize = humanize.MiByte
Copy link
Member

Choose a reason for hiding this comment

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

should this be const? - can you add a comment..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can make that constant too as this util func is used only by us.

@@ -59,3 +64,20 @@ func (w *WriteOnCloser) HasWritten() bool { return w.hasWritten }
func WriteOnClose(w io.Writer) *WriteOnCloser {
return &WriteOnCloser{w, false}
}

func AppendFile(dst string, src string) error {
Copy link
Member

Choose a reason for hiding this comment

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

A comment and a test would be needed..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, will add

@@ -833,6 +833,7 @@ func (xl xlObjects) listObjectParts(bucket, object, uploadID string, partNumberM
result.Object = object
result.UploadID = uploadID
result.MaxParts = maxParts
result.PartNumberMarker = partNumberMarker
Copy link
Member

Choose a reason for hiding this comment

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

should this be fixed outside this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unit tests were failing which required this fix. The refactor exposed this bug.

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 add in a separate PR ? This should be reproducible outside of this PR as well right ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, while making the changes I fixed this bug and this broke the tests (as tests were itself incorrect), so the tests needed a fix as well. I can do this in separate PR and retain the bug in the code and tests in this PR. Probably the effort is not worth it at this point since it's all fixed.

Copy link
Member

Choose a reason for hiding this comment

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

Okay then it's fine.

}
sort.SliceStable(uploadIDs, func(i int, j int) bool {
Copy link
Member

Choose a reason for hiding this comment

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

Any particular reason to use sort.SliceStable instead of sort.Slice if yes can you add relevant comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

golang doc says:

// Slice sorts the provided slice given the provided less function.                                                                                                                                                
//                                                                                                                                                                                                                 
// The sort is not guaranteed to be stable. For a stable sort, use                                                                                                                                                 
// SliceStable.                                                                                                                                                                                                    
//                                                                                                                                                                                                                 
// The function panics if the provided interface is not a slice.                                                                                                                                                   
func Slice(slice interface{}, less func(i, j int) bool) {                                                                                                                                                          

So we should replace all our sort.Slice with the stable version

Copy link
Member

Choose a reason for hiding this comment

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

That is incorrect way to look at it. Stable sort is needed when we are sorting based on two or more distinct elements. It is not useful for us and has performance penalty.

When equal elements are indistinguishable, such as with integers, or more generally, any data where the entire element is the key, stability is not an issue. Stability is also not an issue if all keys are different.

Copy link
Member

Choose a reason for hiding this comment

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

Nowhere in our code we have requirements for sorting based on two or more distinct elements. For example if you say we sort based on object name and object modified time then stable sort makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assumed that unstable = unreliable. Will fix this.

@krishnasrinivas krishnasrinivas changed the title [WIP] Lock free multipart backend implementation for FS [Lock free multipart backend implementation for FS Jan 16, 2018
@krishnasrinivas krishnasrinivas changed the title [Lock free multipart backend implementation for FS Lock free multipart backend implementation for FS Jan 16, 2018
@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 6 times, most recently from 18908d5 to e24bcbf Compare January 16, 2018 03:49
cmd/format-fs.go Outdated
@@ -41,14 +43,20 @@ type formatFSV1 struct {
} `json:"fs"`
}

// formatFSV2 - structure is same as formatFSV1. But the multipart backend
// structure is flat instead of hieararchy now.
Copy link
Member

Choose a reason for hiding this comment

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

Typo 'hieararchy'

// 1. The last PutObjectPart triggers go-routine fs.backgroundAppend, this go-routine has not started yet.
// 2. Now CompleteMultipartUpload gets called which sees that lastPart is not appended and starts appending
// from the beginning
fs.backgroundAppend(bucket, object, uploadID)
Copy link
Member

Choose a reason for hiding this comment

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

Should this still be called backgroundAppend() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, because it still appends in the background (though it is not in a long lasting go-routine listening on a channel)

ticker.Stop()
return
case <-ticker.C:
now := time.Now()
Copy link
Member

Choose a reason for hiding this comment

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

do you not want to use UTCNow() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no because fi.Modtime() (which we use to compare with now) does not return in UTC

Copy link
Member

Choose a reason for hiding this comment

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

Are you sure ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

check this:

krishna@escape:~/dev/goprogs$ cat mtime.go
package main

import (
	"fmt"
	"log"
	"os"
	"time"
)

func main() {
	fmt.Println(time.Now(), time.Now().UTC())
	fi, err := os.Stat("mtime.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fi.ModTime())
}
krishna@escape:~/dev/goprogs$ touch mtime.go
krishna@escape:~/dev/goprogs$ go run mtime.go
2018-01-17 12:44:04.361967289 -0800 PST m=+0.000160832 2018-01-17 20:44:04.361967415 +0000 UTC
2018-01-17 12:44:00.791171574 -0800 PST
krishna@escape:~/dev/goprogs$ 

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, looks like it does not matter as time package abstracts it:

krishna@escape:~/dev/goprogs$ cat mtime.go
package main

import (
	"fmt"
	"log"
	"os"
	"time"
)

func main() {
	now := time.Now()
	nowUTC := time.Now().UTC()
	fi, err := os.Stat("mtime.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(now.Sub(fi.ModTime()), nowUTC.Sub(fi.ModTime()))
}
krishna@escape:~/dev/goprogs$ go run mtime.go
44.118449376s 44.118449493s
krishna@escape:~/dev/goprogs$ 

Copy link
Member

Choose a reason for hiding this comment

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

So they manage it for us..

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 3 times, most recently from dfb3f60 to 523863e Compare January 18, 2018 21:23
@codecov
Copy link

codecov bot commented Jan 18, 2018

Codecov Report

Merging #5401 into master will decrease coverage by 0.18%.
The diff coverage is 70.55%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #5401      +/-   ##
==========================================
- Coverage   61.82%   61.63%   -0.19%     
==========================================
  Files         201      201              
  Lines       29516    29072     -444     
==========================================
- Hits        18248    17919     -329     
+ Misses       9856     9769      -87     
+ Partials     1412     1384      -28
Impacted Files Coverage Δ
cmd/fs-v1-metadata.go 78.5% <ø> (-5.04%) ⬇️
pkg/ioutil/ioutil.go 71.42% <ø> (ø) ⬆️
pkg/lock/lock_nix.go 48.71% <0%> (-2.64%) ⬇️
cmd/xl-v1-multipart.go 70.28% <100%> (+0.03%) ⬆️
cmd/fs-v1-helpers.go 69.23% <100%> (-1.05%) ⬇️
cmd/object-handlers.go 79.75% <100%> (+0.02%) ⬆️
cmd/format-fs.go 49.69% <47.36%> (+8.95%) ⬆️
pkg/ioutil/append-file_nix.go 66.66% <66.66%> (ø)
cmd/fs-v1-multipart.go 68.32% <71.95%> (+1.39%) ⬆️
cmd/fs-v1.go 73.46% <89.28%> (-0.05%) ⬇️
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3ea28e9...de58159. Read the comment docs.

@@ -0,0 +1,27 @@
package ioutil
Copy link
Member

Choose a reason for hiding this comment

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

License header..

@@ -0,0 +1,27 @@
// +build !windows
Copy link
Member

Choose a reason for hiding this comment

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

License header..

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 3 times, most recently from 0246692 to 61aaf64 Compare January 20, 2018 01:58
@balamurugana
Copy link
Member

Error running mint automation
+ mkdir -p 5401-0246692/gopath/src/github.com/minio
+ git -C 5401-0246692/gopath/src/github.com/minio clone --quiet https://github.com/minio/minio.git
+ git -C 5401-0246692/gopath/src/github.com/minio/minio remote add minio https://github.com/minio/minio.git
+ git -C 5401-0246692/gopath/src/github.com/minio/minio fetch --quiet minio pull/5401/head:pr5401
+ git -C 5401-0246692/gopath/src/github.com/minio/minio checkout --quiet pr5401
+ GOPATH=/home/bala/mintauto/5401-0246692/gopath
+ make -C 5401-0246692/gopath/src/github.com/minio/minio --quiet
# github.com/minio/minio/cmd
cmd/fs-v1-helpers.go:25:2: runtime redeclared as imported package name
	previous declaration at cmd/fs-v1-helpers.go:23:2
make: *** [build] Error 2

@balamurugana
Copy link
Member

Error running mint automation
+ mkdir -p 5401-61aaf64/gopath/src/github.com/minio
+ git -C 5401-61aaf64/gopath/src/github.com/minio clone --quiet https://github.com/minio/minio.git
+ git -C 5401-61aaf64/gopath/src/github.com/minio/minio remote add minio https://github.com/minio/minio.git
+ git -C 5401-61aaf64/gopath/src/github.com/minio/minio fetch --quiet minio pull/5401/head:pr5401
+ git -C 5401-61aaf64/gopath/src/github.com/minio/minio checkout --quiet pr5401
+ GOPATH=/home/bala/mintauto/5401-61aaf64/gopath
+ make -C 5401-61aaf64/gopath/src/github.com/minio/minio --quiet
# github.com/minio/minio/cmd
cmd/fs-v1-helpers.go:25:2: runtime redeclared as imported package name
	previous declaration at cmd/fs-v1-helpers.go:23:2
make: *** [build] Error 2

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 3 times, most recently from 6f80cc8 to 872d718 Compare January 22, 2018 07:39
@balamurugana
Copy link
Member

Mint Automation

Test Result
mint-xl.sh ✔️
mint-dist-xl.sh ✔️
mint-fs.sh more...
mint-gateway-s3.sh more...
mint-gateway-azure.sh more...

5401-872d718/mint-gateway-s3.sh.log:

Running with
SERVER_ENDPOINT: minikube:31072
ACCESS_KEY:      AKIAJH7GQKYNU3C2ADXA
SECRET_KEY:      ***REDACTED***
ENABLE_HTTPS:    0
SERVER_REGION:   us-east-1
MINT_DATA_DIR:   /mint/data
MINT_MODE:       core

To get logs, run 'docker cp 8442cfa4e79d:/mint/log /tmp/mint-logs'
(1/11) Running aws-sdk-go tests ... done in 3 seconds
(2/11) Running aws-sdk-php tests ... done in 1 minutes and 16 seconds
(3/11) Running aws-sdk-ruby tests ... done in 1 minutes and 27 seconds
(4/11) Running awscli tests ... done in 8 minutes and 8 seconds
(5/11) Running mc tests ... done in 6 minutes and 16 seconds
(6/11) Running minio-dotnet tests ... done in 2 minutes and 4 seconds
(7/11) Running minio-go tests ... done in 18 seconds
(8/11) Running minio-java tests ... FAILED in 59 seconds
{
  "name": "minio-java",
  "function": "setBucketPolicy(String bucketName, String objectPrefix, PolicyType policyType)",
  "duration": 6537,
  "status": "FAIL",
  "error": "error occured\nErrorResponse(code=AccessDenied, message=Access Denied., bucketName=null, objectName=null, resource=/minio-java-test-13n2nkd/set-bucket-policy-read-write/minio-java-test-lq3sk2, requestId=3L137, hostId=3L137)\nrequest={method=GET, url=http://minikube:31072/minio-java-test-13n2nkd/set-bucket-policy-read-write/minio-java-test-lq3sk2, headers=Host: minikube:31072\nUser-Agent: Minio (amd64; amd64) minio-java/dev\nx-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nx-amz-date: 20180122T080335Z\nAuthorization: AWS4-HMAC-SHA256 Credential=*REDACTED*/20180122/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=*REDACTED*\n}\nresponse={code=403, headers=Accept-Ranges: bytes\nContent-Type: application/xml\nServer: Minio/DEVELOPMENT.2018-01-22T07-39-30Z (linux; amd64)\nVary: Origin\nX-Amz-Request-Id: 150C1322FDBCAFC6\nDate: Mon, 22 Jan 2018 08:03:35 GMT\nTransfer-Encoding: chunked\n}\n >>> [io.minio.MinioClient.execute(MinioClient.java:1205), io.minio.MinioClient.executeGet(MinioClient.java:1298), io.minio.MinioClient.getObject(MinioClient.java:1606), io.minio.MinioClient.getObject(MinioClient.java:1510), FunctionalTest.testSetBucketPolicy(FunctionalTest.java:2427), FunctionalTest.setBucketPolicy_test4(FunctionalTest.java:2482), FunctionalTest.runQuickTests(FunctionalTest.java:2788), FunctionalTest.main(FunctionalTest.java:2830)]"
}

Executed 7 out of 11 tests successfully.

5401-872d718/mint-gateway-azure.sh.log:

Running with
SERVER_ENDPOINT: minikube:31251
ACCESS_KEY:      minioazure1
SECRET_KEY:      ***REDACTED***
ENABLE_HTTPS:    0
SERVER_REGION:   us-east-1
MINT_DATA_DIR:   /mint/data
MINT_MODE:       core

To get logs, run 'docker cp 84945b04a16d:/mint/log /tmp/mint-logs'
(1/11) Running aws-sdk-go tests ... done in 1 seconds
(2/11) Running aws-sdk-php tests ... done in 2 minutes and 55 seconds
(3/11) Running aws-sdk-ruby tests ... done in 52 seconds
(4/11) Running awscli tests ... done in 7 minutes and 37 seconds
(5/11) Running mc tests ... done in 6 minutes and 17 seconds
(6/11) Running minio-dotnet tests ... done in 1 minutes and 20 seconds
(7/11) Running minio-go tests ... done in 2 seconds
(8/11) Running minio-java tests ... done in 43 seconds
(9/11) Running minio-js tests ... done in 2 minutes and 4 seconds
(10/11) Running minio-py tests ... FAILED in 1 minutes and 6 seconds
{
  "error": "Traceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1127, in test_list_incomplete_uploads\n    raise ValueError(\"Listed upload ids do not match the created ids\")\nValueError: Listed upload ids do not match the created ids\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1807, in main\n    test_list_incomplete_uploads(client, log_output)\n  File \"/mint/run/core/minio-py/tests.py\", line 1129, in test_list_incomplete_uploads\n    raise Exception(err)\nException: Listed upload ids do not match the created ids\n",
  "args": {
    "bucket_name": "minio-py-test-41351fe7-7182-43e4-87a5-af1eb6870125",
    "object_name": "eb5f7a3b-6d4e-48c8-92d3-7975ba0c9ced"
  },
  "name": "minio-py:test_list_incomplete_uploads",
  "function": "list_incomplete_uploads(bucket_name, prefix, recursive)",
  "duration": 1341,
  "message": "Listed upload ids do not match the created ids",
  "status": "FAIL"
}

Executed 9 out of 11 tests successfully.

5401-872d718/mint-fs.sh.log:

Running with
SERVER_ENDPOINT: minikube:31549
ACCESS_KEY:      minio
SECRET_KEY:      ***REDACTED***
ENABLE_HTTPS:    0
SERVER_REGION:   us-east-1
MINT_DATA_DIR:   /mint/data
MINT_MODE:       core

To get logs, run 'docker cp c6380a3fce21:/mint/log /tmp/mint-logs'
(1/11) Running aws-sdk-go tests ... done in 1 seconds
(2/11) Running aws-sdk-php tests ... done in 52 seconds
(3/11) Running aws-sdk-ruby tests ... done in 7 seconds
(4/11) Running awscli tests ... done in 9 minutes and 26 seconds
(5/11) Running mc tests ... done in 8 minutes and 10 seconds
(6/11) Running minio-dotnet tests ... done in 2 minutes and 19 seconds
(7/11) Running minio-go tests ... done in 0 seconds
(8/11) Running minio-java tests ... done in 20 seconds
(9/11) Running minio-js tests ... done in 6 minutes and 35 seconds
(10/11) Running minio-py tests ... FAILED in 5 minutes and 37 seconds
{
  "error": "Traceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1127, in test_list_incomplete_uploads\n    raise ValueError(\"Listed upload ids do not match the created ids\")\nValueError: Listed upload ids do not match the created ids\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1129, in test_list_incomplete_uploads\n    raise Exception(err)\nException: Listed upload ids do not match the created ids\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1135, in test_list_incomplete_uploads\n    upload_id)\n  File \"/usr/local/lib/python3.5/dist-packages/minio/api.py\", line 1593, in _remove_incomplete_upload\n    headers={})\n  File \"/usr/local/lib/python3.5/dist-packages/minio/api.py\", line 1801, in _url_open\n    object_name).get_exception()\nminio.error.NoSuchUpload: NoSuchUpload: message: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart               upload might have been aborted or completed.\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/mint/run/core/minio-py/tests.py\", line 1807, in main\n    test_list_incomplete_uploads(client, log_output)\n  File \"/mint/run/core/minio-py/tests.py\", line 1138, in test_list_incomplete_uploads\n    raise Exception(err)\nException: NoSuchUpload: message: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart               upload might have been aborted or completed.\n",
  "duration": 101,
  "status": "FAIL",
  "message": "NoSuchUpload: message: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart               upload might have been aborted or completed.",
  "name": "minio-py:test_list_incomplete_uploads",
  "function": "list_incomplete_uploads(bucket_name, prefix, recursive)",
  "args": {
    "bucket_name": "minio-py-test-a4a5b894-a03a-4bad-bcd4-f24fd40fa8ff",
    "object_name": "e4b1ebb7-eeca-4434-adc7-e6688c6c4c32"
  }
}

Executed 9 out of 11 tests successfully.

cmd/format-fs.go Outdated
@@ -98,19 +115,56 @@ func formatFSGetVersion(r io.ReadSeeker) (string, error) {
return format.FS.Version, nil
}

// Migrate from V1 to V2. V2 implements new backend format for mutipart
Copy link
Member

Choose a reason for hiding this comment

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

Typo mutipart

cmd/format-fs.go Outdated
if err != nil {
return err
}
if version != formatFSVersionV1 {
if version != formatFSVersionV2 {
return fmt.Errorf(`%s file: expected FS version: %s, found FS version: %s`, formatConfigFile, formatFSVersionV1, version)
Copy link
Member

Choose a reason for hiding this comment

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

Should be formatFSVersionV2

@@ -62,7 +62,7 @@ func TestFSFormatFS(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if version != formatFSVersionV1 {
if version != formatFSVersionV2 {
t.Fatalf(`expected: %s, got: %s`, formatFSVersionV1, version)
Copy link
Member

Choose a reason for hiding this comment

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

expected is V2.

@@ -0,0 +1,43 @@
/*
* Minio Cloud Storage, (C) 2017 Minio, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

Should be 2018?

// +build !windows

/*
* Minio Cloud Storage, (C) 2017 Minio, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

Should be 2018?

func (fs *fsObjects) decodePartFile(name string) (partNumber int, md5hex string, err error) {
result := strings.Split(name, ".")
if len(result) != 2 {
return -1, "", errUnexpected
Copy link
Member

Choose a reason for hiding this comment

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

A special -1 part number seems unnecessary as valid part numbers start from 1 anyway. In addition go conventions-wise, when error is not nil, the other return values must be ignored.

uploadIDs := uploadsV1{}
if _, err = uploadIDs.ReadFrom(rlk.LockedFile); err != nil {
return nil, false, err
return -1, "", errUnexpected
Copy link
Member

Choose a reason for hiding this comment

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

Same as above.

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 6 times, most recently from 1f7b89c to 9d4a368 Compare January 24, 2018 23:37
multipartMarkerPath = pathJoin(bucket, keyMarker)
lenEntries := len(entries)
if lenEntries == 0 {
errorIf(errUnexpected, "%s is empty", uploadIDDir)
Copy link
Member

Choose a reason for hiding this comment

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

We don't need to do this i think, since entries range would be skipped and returned quickly. Also there is no reason to print an error lo here..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added it to log it as we should never be in this situation. But we dont lose much by removing this error message too, because I think we will never hit this case. One possible situation where we will hit this case is when cleanup has cleaned the uploadID and not deleted the directory and just then if backgroundAppend sees 0 entries. This is a highly improbable case,so I will delete this logging.

if err := checkNewMultipartArgs(bucket, object, fs); err != nil {
return "", err
return "", toObjectErr(errors.Trace(err), bucket)
Copy link
Member

Choose a reason for hiding this comment

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

You could avoid double tracing here err returned by checkNewMultipartArgs is already traced.

}

if _, err := fs.statBucketDir(bucket); err != nil {
return "", toObjectErr(err, bucket)
return "", toObjectErr(errors.Trace(err), bucket)
Copy link
Member

Choose a reason for hiding this comment

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

You could avoid double tracing here err returned by checkNewMultipartArgs is already traced.

nextPartIndex := fsMeta.ObjectPartIndex(nextPartNum)
if nextPartIndex == -1 {
return
if err = ioutil.WriteFile(pathJoin(uploadIDDir, fsMetaJSONFile), fsMetaBytes, 0644); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

You can use WriteTo interface here @krishnasrinivas and change the WriteTo to be.

func (m *fsMetaV1) WriteTo(w io.Writer) (n int64, err error) {
        var metadataBytes []byte
        metadataBytes, err = json.Marshal(m)
        if err != nil {
                return 0, errors.Trace(err)
        }

        t, ok  := w.(*lock.LockedFile)
        if ok {
              if err =  t.Truncate(0); err != nil {
                return 0, errors.Trace(err)
              }
        }

        if _, err = lk.Write(metadataBytes); err != nil {
                return 0, errors.Trace(err)
        }

        // Success.
        return int64(len(metadataBytes)), nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about this, but using WriteTo() does not give any advantage over ioutil.WriteFile().

On the other hand if WriteTo and ReadFrom takes lock.LockedFile the advantage is compiler always type checks that it reads and writes from a locked file. i.e we can have a convention that all access to the main namespace fs.json should be done through fsMeta.WriteTo and fsMeta.ReadFrom

Copy link
Member

Choose a reason for hiding this comment

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

Okay that makes sense @krishnasrinivas

if err := checkCompleteMultipartArgs(bucket, object, fs); err != nil {
return oi, err
return oi, toObjectErr(errors.Trace(err))
Copy link
Member

Choose a reason for hiding this comment

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

Avoid double tracing..


fsMeta := fsMetaV1{}
// Read saved fs metadata for ongoing multipart.
fsMetaBuf, err := ioutil.ReadFile(pathJoin(uploadIDDir, fsMetaJSONFile))
Copy link
Member

Choose a reason for hiding this comment

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

You could use ReadFrom()

// delete the bucket/object/uploadid
fs.rwPool.Close(fsMetaPath)
fsRemoveAll(uploadIDDir)
// if err := fsRemoveAll(uploadIDDir); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Remove the comment.. ?

@donatello
Copy link
Member

Build is failing.

@krishnasrinivas krishnasrinivas force-pushed the fs-multipart-no-lock branch 3 times, most recently from 012bebe to 6e5a7d8 Compare January 31, 2018 01:21
Copy link
Member

@harshavardhana harshavardhana left a comment

Choose a reason for hiding this comment

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

LGTM

@kannappanr kannappanr merged commit 3b2486e into minio:master Jan 31, 2018
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.

None yet

5 participants