mirror of
https://github.com/minio/minio.git
synced 2025-11-07 12:52:58 -05:00
avoid repeated large allocations for large parts (#17968)
objects with 10,000 parts and many of them can cause a large memory spike which can potentially lead to OOM due to lack of GC. with previous PR reducing the memory usage significantly in #17963, this PR reduces this further by 80% under repeated calls. Scanner sub-system has no use for the slice of Parts(), it is better left empty. ``` benchmark old ns/op new ns/op delta BenchmarkToFileInfo/ToFileInfo-8 295658 188143 -36.36% benchmark old allocs new allocs delta BenchmarkToFileInfo/ToFileInfo-8 61 60 -1.64% benchmark old bytes new bytes delta BenchmarkToFileInfo/ToFileInfo-8 1097210 227255 -79.29% ```
This commit is contained in:
@@ -432,13 +432,13 @@ func (j xlMetaV2Version) getVersionID() [16]byte {
|
||||
}
|
||||
|
||||
// ToFileInfo returns FileInfo of the underlying type.
|
||||
func (j *xlMetaV2Version) ToFileInfo(volume, path string) (fi FileInfo, err error) {
|
||||
func (j *xlMetaV2Version) ToFileInfo(volume, path string, allParts bool) (fi FileInfo, err error) {
|
||||
if j == nil {
|
||||
return fi, errFileNotFound
|
||||
}
|
||||
switch j.Type {
|
||||
case ObjectType:
|
||||
fi, err = j.ObjectV2.ToFileInfo(volume, path)
|
||||
fi, err = j.ObjectV2.ToFileInfo(volume, path, allParts)
|
||||
case DeleteType:
|
||||
fi, err = j.DeleteMarker.ToFileInfo(volume, path)
|
||||
case LegacyType:
|
||||
@@ -585,7 +585,7 @@ func (j *xlMetaV2Object) Signature() [4]byte {
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (j xlMetaV2Object) ToFileInfo(volume, path string) (FileInfo, error) {
|
||||
func (j xlMetaV2Object) ToFileInfo(volume, path string, allParts bool) (FileInfo, error) {
|
||||
versionID := ""
|
||||
var uv uuid.UUID
|
||||
// check if the version is not "null"
|
||||
@@ -599,18 +599,21 @@ func (j xlMetaV2Object) ToFileInfo(volume, path string) (FileInfo, error) {
|
||||
ModTime: time.Unix(0, j.ModTime).UTC(),
|
||||
VersionID: versionID,
|
||||
}
|
||||
fi.Parts = make([]ObjectPartInfo, len(j.PartNumbers))
|
||||
for i := range fi.Parts {
|
||||
fi.Parts[i].Number = j.PartNumbers[i]
|
||||
fi.Parts[i].Size = j.PartSizes[i]
|
||||
if len(j.PartETags) == len(fi.Parts) {
|
||||
fi.Parts[i].ETag = j.PartETags[i]
|
||||
}
|
||||
fi.Parts[i].ActualSize = j.PartActualSizes[i]
|
||||
if len(j.PartIndices) == len(fi.Parts) {
|
||||
fi.Parts[i].Index = j.PartIndices[i]
|
||||
if allParts {
|
||||
fi.Parts = make([]ObjectPartInfo, len(j.PartNumbers))
|
||||
for i := range fi.Parts {
|
||||
fi.Parts[i].Number = j.PartNumbers[i]
|
||||
fi.Parts[i].Size = j.PartSizes[i]
|
||||
if len(j.PartETags) == len(fi.Parts) {
|
||||
fi.Parts[i].ETag = j.PartETags[i]
|
||||
}
|
||||
fi.Parts[i].ActualSize = j.PartActualSizes[i]
|
||||
if len(j.PartIndices) == len(fi.Parts) {
|
||||
fi.Parts[i].Index = j.PartIndices[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fi.Erasure.Checksums - is left empty since we do not have any
|
||||
// whole checksums for many years now, no need to allocate.
|
||||
|
||||
@@ -1719,7 +1722,7 @@ func (x *xlMetaV2) AddLegacy(m *xlMetaV1Object) error {
|
||||
|
||||
// ToFileInfo converts xlMetaV2 into a common FileInfo datastructure
|
||||
// for consumption across callers.
|
||||
func (x xlMetaV2) ToFileInfo(volume, path, versionID string, inclFreeVers bool) (fi FileInfo, err error) {
|
||||
func (x xlMetaV2) ToFileInfo(volume, path, versionID string, inclFreeVers, allParts bool) (fi FileInfo, err error) {
|
||||
var uv uuid.UUID
|
||||
if versionID != "" && versionID != nullVersionID {
|
||||
uv, err = uuid.Parse(versionID)
|
||||
@@ -1747,7 +1750,7 @@ func (x xlMetaV2) ToFileInfo(volume, path, versionID string, inclFreeVers bool)
|
||||
if inclFreeVers && !freeFound {
|
||||
// ignore unmarshalling errors, will return errFileNotFound in that case
|
||||
if _, err := freeVersion.unmarshalV(x.metaV, ver.meta); err == nil {
|
||||
if freeFi, err = freeVersion.ToFileInfo(volume, path); err == nil {
|
||||
if freeFi, err = freeVersion.ToFileInfo(volume, path, allParts); err == nil {
|
||||
freeFi.IsLatest = true // when this is returned, it would be the latest free version remaining.
|
||||
freeFound = true
|
||||
}
|
||||
@@ -1775,7 +1778,7 @@ func (x xlMetaV2) ToFileInfo(volume, path, versionID string, inclFreeVers bool)
|
||||
if _, err := version.unmarshalV(x.metaV, ver.meta); err != nil {
|
||||
return fi, err
|
||||
}
|
||||
if fi, err = version.ToFileInfo(volume, path); err != nil {
|
||||
if fi, err = version.ToFileInfo(volume, path, allParts); err != nil {
|
||||
return fi, err
|
||||
}
|
||||
fi.IsLatest = isLatest
|
||||
@@ -1803,7 +1806,7 @@ func (x xlMetaV2) ToFileInfo(volume, path, versionID string, inclFreeVers bool)
|
||||
// versions returns error for unexpected entries.
|
||||
// showPendingDeletes is set to true if ListVersions needs to list objects marked deleted
|
||||
// but waiting to be replicated
|
||||
func (x xlMetaV2) ListVersions(volume, path string) ([]FileInfo, error) {
|
||||
func (x xlMetaV2) ListVersions(volume, path string, allParts bool) ([]FileInfo, error) {
|
||||
versions := make([]FileInfo, 0, len(x.versions))
|
||||
var err error
|
||||
|
||||
@@ -1813,7 +1816,7 @@ func (x xlMetaV2) ListVersions(volume, path string) ([]FileInfo, error) {
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
fi, err := dst.ToFileInfo(volume, path)
|
||||
fi, err := dst.ToFileInfo(volume, path, allParts)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
@@ -2024,7 +2027,7 @@ type xlMetaBuf []byte
|
||||
|
||||
// ToFileInfo converts xlMetaV2 into a common FileInfo datastructure
|
||||
// for consumption across callers.
|
||||
func (x xlMetaBuf) ToFileInfo(volume, path, versionID string) (fi FileInfo, err error) {
|
||||
func (x xlMetaBuf) ToFileInfo(volume, path, versionID string, allParts bool) (fi FileInfo, err error) {
|
||||
var uv uuid.UUID
|
||||
if versionID != "" && versionID != nullVersionID {
|
||||
uv, err = uuid.Parse(versionID)
|
||||
@@ -2071,7 +2074,7 @@ func (x xlMetaBuf) ToFileInfo(volume, path, versionID string) (fi FileInfo, err
|
||||
if _, err := version.unmarshalV(metaV, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
if fi, err = version.ToFileInfo(volume, path); err != nil {
|
||||
if fi, err = version.ToFileInfo(volume, path, allParts); err != nil {
|
||||
return err
|
||||
}
|
||||
fi.IsLatest = isLatest
|
||||
@@ -2095,7 +2098,7 @@ func (x xlMetaBuf) ToFileInfo(volume, path, versionID string) (fi FileInfo, err
|
||||
// versions returns error for unexpected entries.
|
||||
// showPendingDeletes is set to true if ListVersions needs to list objects marked deleted
|
||||
// but waiting to be replicated
|
||||
func (x xlMetaBuf) ListVersions(volume, path string) ([]FileInfo, error) {
|
||||
func (x xlMetaBuf) ListVersions(volume, path string, allParts bool) ([]FileInfo, error) {
|
||||
vers, _, metaV, buf, err := decodeXLHeaders(x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2111,7 +2114,7 @@ func (x xlMetaBuf) ListVersions(volume, path string) ([]FileInfo, error) {
|
||||
if !xl.Valid() {
|
||||
return errFileCorrupt
|
||||
}
|
||||
fi, err := xl.ToFileInfo(volume, path)
|
||||
fi, err := xl.ToFileInfo(volume, path, allParts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user