mirror of
https://github.com/minio/minio.git
synced 2025-01-23 12:43:16 -05:00
ObjectLayer/GetObject: Should return the right error value. Fix done in FS and XL. (#2133)
fixes #2117
This commit is contained in:
parent
5102a5877e
commit
ae80f8ca35
5
fs-v1.go
5
fs-v1.go
@ -248,7 +248,7 @@ func (fs fsObjects) GetObject(bucket, object string, offset int64, length int64,
|
|||||||
}
|
}
|
||||||
// Allocate a staging buffer.
|
// Allocate a staging buffer.
|
||||||
buf := make([]byte, int(bufSize))
|
buf := make([]byte, int(bufSize))
|
||||||
for totalLeft > 0 {
|
for {
|
||||||
// Figure out the right size for the buffer.
|
// Figure out the right size for the buffer.
|
||||||
curLeft := bufSize
|
curLeft := bufSize
|
||||||
if totalLeft < bufSize {
|
if totalLeft < bufSize {
|
||||||
@ -282,6 +282,9 @@ func (fs fsObjects) GetObject(bucket, object string, offset int64, length int64,
|
|||||||
err = er
|
err = er
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if totalLeft == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Returns any error.
|
// Returns any error.
|
||||||
return toObjectErr(err, bucket, object)
|
return toObjectErr(err, bucket, object)
|
||||||
|
@ -67,6 +67,11 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i
|
|||||||
return toObjectErr(errXLReadQuorum, bucket, object)
|
return toObjectErr(errXLReadQuorum, bucket, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If all the disks returned error, we return error.
|
||||||
|
if err := reduceErrs(errs); err != nil {
|
||||||
|
return toObjectErr(err, bucket, object)
|
||||||
|
}
|
||||||
|
|
||||||
// List all online disks.
|
// List all online disks.
|
||||||
onlineDisks, highestVersion, err := xl.listOnlineDisks(metaArr, errs)
|
onlineDisks, highestVersion, err := xl.listOnlineDisks(metaArr, errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,6 +23,59 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Returns nil even if one of the slice elements is nil.
|
||||||
|
// Else returns the error which occours the most.
|
||||||
|
func reduceErrs(errs []error) error {
|
||||||
|
// In case the error type is not in the known error list.
|
||||||
|
var unknownErr = errors.New("unknown error")
|
||||||
|
var errTypes = []struct {
|
||||||
|
err error // error type
|
||||||
|
count int // occurance count
|
||||||
|
}{
|
||||||
|
// List of known error types. Any new type that can be returned from StorageAPI should
|
||||||
|
// be added to this list. Most common errors are listed here.
|
||||||
|
{errDiskNotFound, 0}, {errFaultyDisk, 0}, {errFileAccessDenied, 0},
|
||||||
|
{errFileNotFound, 0}, {errFileNameTooLong, 0}, {errVolumeNotFound, 0},
|
||||||
|
{errDiskFull, 0},
|
||||||
|
// unknownErr count - count of the number of unknown errors.
|
||||||
|
{unknownErr, 0},
|
||||||
|
}
|
||||||
|
// In case unknownErr count occours maximum number of times, unknownErrType is used to
|
||||||
|
// to store it so that it can be used for the return error type.
|
||||||
|
var unknownErrType error
|
||||||
|
|
||||||
|
// For each err in []errs increment the corresponding count value.
|
||||||
|
for _, err := range errs {
|
||||||
|
if err == nil {
|
||||||
|
// Return nil even if one of the elements is nil.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range errTypes {
|
||||||
|
if errTypes[i].err == err {
|
||||||
|
errTypes[i].count++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if errTypes[i].err == unknownErr {
|
||||||
|
errTypes[i].count++
|
||||||
|
unknownErrType = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max := 0
|
||||||
|
// Get the error type which has the maximum count.
|
||||||
|
for i, errType := range errTypes {
|
||||||
|
if errType.count > errTypes[max].count {
|
||||||
|
max = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errTypes[max].err == unknownErr {
|
||||||
|
// Return the unknown error.
|
||||||
|
return unknownErrType
|
||||||
|
}
|
||||||
|
return errTypes[max].err
|
||||||
|
}
|
||||||
|
|
||||||
// Validates if we have quorum based on the errors with errDiskNotFound.
|
// Validates if we have quorum based on the errors with errDiskNotFound.
|
||||||
func isQuorum(errs []error, minQuorumCount int) bool {
|
func isQuorum(errs []error, minQuorumCount int) bool {
|
||||||
var diskFoundCount int
|
var diskFoundCount int
|
||||||
|
43
xl-v1-utils_test.go
Normal file
43
xl-v1-utils_test.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// Test for reduceErrs.
|
||||||
|
func TestReduceErrs(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
errs []error
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{[]error{errDiskNotFound, errDiskNotFound, errDiskFull}, errDiskNotFound},
|
||||||
|
{[]error{errDiskNotFound, errDiskFull, errDiskFull}, errDiskFull},
|
||||||
|
{[]error{errDiskFull, errDiskNotFound, errDiskFull}, errDiskFull},
|
||||||
|
// A case for error not in the known errors list (refer to func reduceErrs)
|
||||||
|
{[]error{errDiskFull, syscall.EEXIST, syscall.EEXIST}, syscall.EEXIST},
|
||||||
|
{[]error{errDiskNotFound, errDiskNotFound, nil}, nil},
|
||||||
|
{[]error{nil, nil, nil}, nil},
|
||||||
|
}
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
expected := testCase.err
|
||||||
|
got := reduceErrs(testCase.errs)
|
||||||
|
if expected != got {
|
||||||
|
t.Errorf("Test %d : expected %s, got %s", i+1, expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user