mirror of
https://github.com/minio/minio.git
synced 2024-12-25 14:45:54 -05:00
fix: Allow Walk to honor load balanced drives (#10610)
This commit is contained in:
parent
71403be912
commit
23e8390997
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@ -37,6 +37,8 @@ jobs:
|
|||||||
GO111MODULE: on
|
GO111MODULE: on
|
||||||
MINIO_CI_CD: 1
|
MINIO_CI_CD: 1
|
||||||
run: |
|
run: |
|
||||||
|
sudo sysctl net.ipv6.conf.all.disable_ipv6=0
|
||||||
|
sudo sysctl net.ipv6.conf.default.disable_ipv6=0
|
||||||
sudo apt-get install devscripts shellcheck
|
sudo apt-get install devscripts shellcheck
|
||||||
nancy_version=$(curl --retry 10 -Ls -o /dev/null -w "%{url_effective}" https://github.com/sonatype-nexus-community/nancy/releases/latest | sed "s/https:\/\/github.com\/sonatype-nexus-community\/nancy\/releases\/tag\///")
|
nancy_version=$(curl --retry 10 -Ls -o /dev/null -w "%{url_effective}" https://github.com/sonatype-nexus-community/nancy/releases/latest | sed "s/https:\/\/github.com\/sonatype-nexus-community\/nancy\/releases\/tag\///")
|
||||||
curl -L -o nancy https://github.com/sonatype-nexus-community/nancy/releases/download/${nancy_version}/nancy-linux.amd64-${nancy_version} && chmod +x nancy
|
curl -L -o nancy https://github.com/sonatype-nexus-community/nancy/releases/download/${nancy_version}/nancy-linux.amd64-${nancy_version} && chmod +x nancy
|
||||||
|
@ -76,8 +76,8 @@ function start_minio_zone_erasure_sets_ipv6()
|
|||||||
export MINIO_ACCESS_KEY=$ACCESS_KEY
|
export MINIO_ACCESS_KEY=$ACCESS_KEY
|
||||||
export MINIO_SECRET_KEY=$SECRET_KEY
|
export MINIO_SECRET_KEY=$SECRET_KEY
|
||||||
|
|
||||||
"${MINIO[@]}" server --address="[::1]:9000" "http://[::1]:9000${WORK_DIR}/zone-disk-sets{1...4}" "http://[::1]:9001${WORK_DIR}/zone-disk-sets{5...8}" >"$WORK_DIR/zone-minio-9000.log" 2>&1 &
|
"${MINIO[@]}" server --address="[::1]:9000" "http://[::1]:9000${WORK_DIR}/zone-disk-sets{1...4}" "http://[::1]:9001${WORK_DIR}/zone-disk-sets{5...8}" >"$WORK_DIR/zone-minio-ipv6-9000.log" 2>&1 &
|
||||||
"${MINIO[@]}" server --address="[::1]:9001" "http://[::1]:9000${WORK_DIR}/zone-disk-sets{1...4}" "http://[::1]:9001${WORK_DIR}/zone-disk-sets{5...8}" >"$WORK_DIR/zone-minio-9001.log" 2>&1 &
|
"${MINIO[@]}" server --address="[::1]:9001" "http://[::1]:9000${WORK_DIR}/zone-disk-sets{1...4}" "http://[::1]:9001${WORK_DIR}/zone-disk-sets{5...8}" >"$WORK_DIR/zone-minio-ipv6-9001.log" 2>&1 &
|
||||||
|
|
||||||
sleep 40
|
sleep 40
|
||||||
}
|
}
|
||||||
|
@ -1750,17 +1750,17 @@ func (z *erasureZones) Walk(ctx context.Context, bucket, prefix string, results
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var zoneDrivesPerSet []int
|
||||||
|
for _, zone := range z.zones {
|
||||||
|
zoneDrivesPerSet = append(zoneDrivesPerSet, zone.listTolerancePerSet-2)
|
||||||
|
}
|
||||||
|
|
||||||
if opts.WalkVersions {
|
if opts.WalkVersions {
|
||||||
var zonesEntryChs [][]FileInfoVersionsCh
|
var zonesEntryChs [][]FileInfoVersionsCh
|
||||||
for _, zone := range z.zones {
|
for _, zone := range z.zones {
|
||||||
zonesEntryChs = append(zonesEntryChs, zone.startMergeWalksVersions(ctx, bucket, prefix, "", true, ctx.Done()))
|
zonesEntryChs = append(zonesEntryChs, zone.startMergeWalksVersions(ctx, bucket, prefix, "", true, ctx.Done()))
|
||||||
}
|
}
|
||||||
|
|
||||||
var zoneDrivesPerSet []int
|
|
||||||
for _, zone := range z.zones {
|
|
||||||
zoneDrivesPerSet = append(zoneDrivesPerSet, zone.setDriveCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
var zonesEntriesInfos [][]FileInfoVersions
|
var zonesEntriesInfos [][]FileInfoVersions
|
||||||
var zonesEntriesValid [][]bool
|
var zonesEntriesValid [][]bool
|
||||||
for _, entryChs := range zonesEntryChs {
|
for _, entryChs := range zonesEntryChs {
|
||||||
@ -1772,20 +1772,17 @@ func (z *erasureZones) Walk(ctx context.Context, bucket, prefix string, results
|
|||||||
defer close(results)
|
defer close(results)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
entry, quorumCount, zoneIndex, ok := lexicallySortedEntryZoneVersions(zonesEntryChs, zonesEntriesInfos, zonesEntriesValid)
|
entry, quorumCount, _, ok := lexicallySortedEntryZoneVersions(zonesEntryChs, zonesEntriesInfos, zonesEntriesValid)
|
||||||
if !ok {
|
if !ok {
|
||||||
// We have reached EOF across all entryChs, break the loop.
|
// We have reached EOF across all entryChs, break the loop.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if quorumCount >= zoneDrivesPerSet[zoneIndex]/2 {
|
if quorumCount > 0 {
|
||||||
// Read quorum exists proceed
|
|
||||||
for _, version := range entry.Versions {
|
for _, version := range entry.Versions {
|
||||||
results <- version.ToObjectInfo(bucket, version.Name)
|
results <- version.ToObjectInfo(bucket, version.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip entries which do not have quorum
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1793,10 +1790,8 @@ func (z *erasureZones) Walk(ctx context.Context, bucket, prefix string, results
|
|||||||
}
|
}
|
||||||
|
|
||||||
zonesEntryChs := make([][]FileInfoCh, 0, len(z.zones))
|
zonesEntryChs := make([][]FileInfoCh, 0, len(z.zones))
|
||||||
zoneDrivesPerSet := make([]int, 0, len(z.zones))
|
|
||||||
for _, zone := range z.zones {
|
for _, zone := range z.zones {
|
||||||
zonesEntryChs = append(zonesEntryChs, zone.startMergeWalks(ctx, bucket, prefix, "", true, ctx.Done()))
|
zonesEntryChs = append(zonesEntryChs, zone.startMergeWalks(ctx, bucket, prefix, "", true, ctx.Done()))
|
||||||
zoneDrivesPerSet = append(zoneDrivesPerSet, zone.setDriveCount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zonesEntriesInfos := make([][]FileInfo, 0, len(zonesEntryChs))
|
zonesEntriesInfos := make([][]FileInfo, 0, len(zonesEntryChs))
|
||||||
@ -1810,17 +1805,15 @@ func (z *erasureZones) Walk(ctx context.Context, bucket, prefix string, results
|
|||||||
defer close(results)
|
defer close(results)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
entry, quorumCount, zoneIndex, ok := lexicallySortedEntryZone(zonesEntryChs, zonesEntriesInfos, zonesEntriesValid)
|
entry, quorumCount, _, ok := lexicallySortedEntryZone(zonesEntryChs, zonesEntriesInfos, zonesEntriesValid)
|
||||||
if !ok {
|
if !ok {
|
||||||
// We have reached EOF across all entryChs, break the loop.
|
// We have reached EOF across all entryChs, break the loop.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if quorumCount >= zoneDrivesPerSet[zoneIndex]/2 {
|
if quorumCount > 0 {
|
||||||
// Read quorum exists proceed
|
|
||||||
results <- entry.ToObjectInfo(bucket, entry.Name)
|
results <- entry.ToObjectInfo(bucket, entry.Name)
|
||||||
}
|
}
|
||||||
// skip entries which do not have quorum
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1859,6 +1852,7 @@ func (z *erasureZones) HealObjects(ctx context.Context, bucket, prefix string, o
|
|||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicate that first attempt was a success and subsequent loop
|
// Indicate that first attempt was a success and subsequent loop
|
||||||
// knows that its not our first attempt at 'prefix'
|
// knows that its not our first attempt at 'prefix'
|
||||||
err = nil
|
err = nil
|
||||||
@ -1866,6 +1860,7 @@ func (z *erasureZones) HealObjects(ctx context.Context, bucket, prefix string, o
|
|||||||
if zoneIndex >= len(zoneDrivesPerSet) || zoneIndex < 0 {
|
if zoneIndex >= len(zoneDrivesPerSet) || zoneIndex < 0 {
|
||||||
return fmt.Errorf("invalid zone index returned: %d", zoneIndex)
|
return fmt.Errorf("invalid zone index returned: %d", zoneIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
if quorumCount == zoneDrivesPerSet[zoneIndex] && opts.ScanMode == madmin.HealNormalScan {
|
if quorumCount == zoneDrivesPerSet[zoneIndex] && opts.ScanMode == madmin.HealNormalScan {
|
||||||
// Skip good entries.
|
// Skip good entries.
|
||||||
continue
|
continue
|
||||||
|
18
cmd/net.go
18
cmd/net.go
@ -189,21 +189,13 @@ func isHostIP(ipAddress string) bool {
|
|||||||
// Note: The check method tries to listen on given port and closes it.
|
// Note: The check method tries to listen on given port and closes it.
|
||||||
// It is possible to have a disconnected client in this tiny window of time.
|
// It is possible to have a disconnected client in this tiny window of time.
|
||||||
func checkPortAvailability(host, port string) (err error) {
|
func checkPortAvailability(host, port string) (err error) {
|
||||||
network := []string{"tcp", "tcp4", "tcp6"}
|
l, err := net.Listen("tcp", net.JoinHostPort(host, port))
|
||||||
for _, n := range network {
|
if err != nil {
|
||||||
l, err := net.Listen(n, net.JoinHostPort(host, port))
|
return err
|
||||||
if err == nil {
|
}
|
||||||
// As we are able to listen on this network, the port is not in use.
|
// As we are able to listen on this network, the port is not in use.
|
||||||
// Close the listener and continue check other networks.
|
// Close the listener and continue check other networks.
|
||||||
if err = l.Close(); err != nil {
|
return l.Close()
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractHostPort - extracts host/port from many address formats
|
// extractHostPort - extracts host/port from many address formats
|
||||||
|
@ -2788,7 +2788,8 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
|
|||||||
if rec.Code == http.StatusOK {
|
if rec.Code == http.StatusOK {
|
||||||
// Verify whether the bucket obtained object is same as the one created.
|
// Verify whether the bucket obtained object is same as the one created.
|
||||||
if !bytes.Equal(testCase.expectedContent, actualContent) {
|
if !bytes.Equal(testCase.expectedContent, actualContent) {
|
||||||
t.Errorf("Test %d : MinIO %s: Object content differs from expected value.", i+1, instanceType)
|
t.Errorf("Test %d : MinIO %s: CompleteMultipart response content differs from expected value. got %s, expecte %s", i+1, instanceType,
|
||||||
|
string(actualContent), string(testCase.expectedContent))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -935,9 +935,16 @@ func testWebHandlerDownloadZip(obj ObjectLayer, instanceType string, t TestErrHa
|
|||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.PutObject(context.Background(), bucket, "a/one", mustGetPutObjReader(t, strings.NewReader(fileOne), int64(len(fileOne)), "", ""), opts)
|
for objName, value := range map[string]string{
|
||||||
obj.PutObject(context.Background(), bucket, "a/b/two", mustGetPutObjReader(t, strings.NewReader(fileTwo), int64(len(fileTwo)), "", ""), opts)
|
"a/one": fileOne,
|
||||||
obj.PutObject(context.Background(), bucket, "a/c/three", mustGetPutObjReader(t, strings.NewReader(fileThree), int64(len(fileThree)), "", ""), opts)
|
"a/b/two": fileTwo,
|
||||||
|
"a/c/three": fileThree,
|
||||||
|
} {
|
||||||
|
_, err = obj.PutObject(context.Background(), bucket, objName, mustGetPutObjReader(t, strings.NewReader(value), int64(len(value)), "", ""), opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test := func(token string) (int, []byte) {
|
test := func(token string) (int, []byte) {
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
@ -23,16 +23,19 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
// GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
|
// GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
|
||||||
// Retrieves information about the amount of space that is available on a disk volume,
|
// Retrieves information about the amount of space that is available on a disk volume,
|
||||||
// which is the total amount of space, the total amount of free space, and the total
|
// which is the total amount of space, the total amount of free space, and the total
|
||||||
// amount of free space available to the user that is associated with the calling thread.
|
// amount of free space available to the user that is associated with the calling thread.
|
||||||
GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
|
GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
|
||||||
|
|
||||||
// GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
|
// GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
|
||||||
// Retrieves information about the specified disk, including the amount of free space on the disk.
|
// Retrieves information about the specified disk, including the amount of free space on the disk.
|
||||||
GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW")
|
GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW")
|
||||||
@ -63,10 +66,18 @@ func GetInfo(path string) (info Info, err error) {
|
|||||||
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
|
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
|
||||||
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
|
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
|
||||||
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
|
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
|
||||||
info = Info{}
|
|
||||||
info.Total = uint64(lpTotalNumberOfBytes)
|
if uint64(lpTotalNumberOfFreeBytes) > uint64(lpTotalNumberOfBytes) {
|
||||||
info.Free = uint64(lpFreeBytesAvailable)
|
return info, fmt.Errorf("detected free space (%d) > total disk space (%d), fs corruption at (%s). please run 'fsck'",
|
||||||
info.FSType = getFSType(path)
|
uint64(lpTotalNumberOfFreeBytes), uint64(lpTotalNumberOfBytes), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
info = Info{
|
||||||
|
Total: uint64(lpTotalNumberOfBytes),
|
||||||
|
Free: uint64(lpTotalNumberOfFreeBytes),
|
||||||
|
Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
|
||||||
|
FSType: getFSType(path),
|
||||||
|
}
|
||||||
|
|
||||||
// Return values of GetDiskFreeSpace()
|
// Return values of GetDiskFreeSpace()
|
||||||
lpSectorsPerCluster := uint32(0)
|
lpSectorsPerCluster := uint32(0)
|
||||||
@ -91,9 +102,5 @@ func GetInfo(path string) (info Info, err error) {
|
|||||||
info.Files = uint64(lpTotalNumberOfClusters)
|
info.Files = uint64(lpTotalNumberOfClusters)
|
||||||
info.Ffree = uint64(lpNumberOfFreeClusters)
|
info.Ffree = uint64(lpNumberOfFreeClusters)
|
||||||
|
|
||||||
if info.Free > info.Total {
|
|
||||||
return info, fmt.Errorf("detected free space (%d) > total disk space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
|
|
||||||
}
|
|
||||||
info.Used = info.Total - info.Free
|
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ package parquet
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.apache.org/thrift.git/lib/go/thrift"
|
"git.apache.org/thrift.git/lib/go/thrift"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.apache.org/thrift.git/lib/go/thrift"
|
"git.apache.org/thrift.git/lib/go/thrift"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,10 +21,12 @@ package sys
|
|||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
|
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user