github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/xl-storage-format-utils.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"errors"
    22  
    23  	"github.com/zeebo/xxh3"
    24  )
    25  
    26  func getFileInfoVersions(xlMetaBuf []byte, volume, path string, allParts bool) (FileInfoVersions, error) {
    27  	fivs, err := getAllFileInfoVersions(xlMetaBuf, volume, path, allParts)
    28  	if err != nil {
    29  		return fivs, err
    30  	}
    31  	n := 0
    32  	for _, fi := range fivs.Versions {
    33  		// Filter our tier object delete marker
    34  		if !fi.TierFreeVersion() {
    35  			fivs.Versions[n] = fi
    36  			n++
    37  		} else {
    38  			fivs.FreeVersions = append(fivs.FreeVersions, fi)
    39  		}
    40  	}
    41  	fivs.Versions = fivs.Versions[:n]
    42  	// Update numversions
    43  	for i := range fivs.Versions {
    44  		fivs.Versions[i].NumVersions = n
    45  	}
    46  	return fivs, nil
    47  }
    48  
    49  func getAllFileInfoVersions(xlMetaBuf []byte, volume, path string, allParts bool) (FileInfoVersions, error) {
    50  	var versions []FileInfo
    51  	var err error
    52  
    53  	if buf, _, e := isIndexedMetaV2(xlMetaBuf); e != nil {
    54  		return FileInfoVersions{}, e
    55  	} else if buf != nil {
    56  		versions, err = buf.ListVersions(volume, path, allParts)
    57  	} else {
    58  		var xlMeta xlMetaV2
    59  		if err := xlMeta.LoadOrConvert(xlMetaBuf); err != nil {
    60  			return FileInfoVersions{}, err
    61  		}
    62  		versions, err = xlMeta.ListVersions(volume, path, allParts)
    63  	}
    64  	if err == nil && len(versions) == 0 {
    65  		// This special case is needed to handle len(xlMeta.versions) == 0
    66  		versions = []FileInfo{
    67  			{
    68  				Volume:   volume,
    69  				Name:     path,
    70  				Deleted:  true,
    71  				IsLatest: true,
    72  				ModTime:  timeSentinel1970,
    73  			},
    74  		}
    75  	}
    76  	if err != nil {
    77  		return FileInfoVersions{}, err
    78  	}
    79  
    80  	return FileInfoVersions{
    81  		Volume:        volume,
    82  		Name:          path,
    83  		Versions:      versions,
    84  		LatestModTime: versions[0].ModTime,
    85  	}, nil
    86  }
    87  
    88  func getFileInfo(xlMetaBuf []byte, volume, path, versionID string, data, allParts bool) (FileInfo, error) {
    89  	var fi FileInfo
    90  	var err error
    91  	var inData xlMetaInlineData
    92  	if buf, data, e := isIndexedMetaV2(xlMetaBuf); e != nil {
    93  		return FileInfo{}, e
    94  	} else if buf != nil {
    95  		inData = data
    96  		fi, err = buf.ToFileInfo(volume, path, versionID, allParts)
    97  		if len(buf) != 0 && errors.Is(err, errFileNotFound) {
    98  			// This special case is needed to handle len(xlMeta.versions) == 0
    99  			return FileInfo{
   100  				Volume:    volume,
   101  				Name:      path,
   102  				VersionID: versionID,
   103  				Deleted:   true,
   104  				IsLatest:  true,
   105  				ModTime:   timeSentinel1970,
   106  			}, nil
   107  		}
   108  	} else {
   109  		var xlMeta xlMetaV2
   110  		if err := xlMeta.LoadOrConvert(xlMetaBuf); err != nil {
   111  			return FileInfo{}, err
   112  		}
   113  		if len(xlMeta.versions) == 0 {
   114  			// This special case is needed to handle len(xlMeta.versions) == 0
   115  			return FileInfo{
   116  				Volume:    volume,
   117  				Name:      path,
   118  				VersionID: versionID,
   119  				Deleted:   true,
   120  				IsLatest:  true,
   121  				ModTime:   timeSentinel1970,
   122  			}, nil
   123  		}
   124  		inData = xlMeta.data
   125  		fi, err = xlMeta.ToFileInfo(volume, path, versionID, false, allParts)
   126  	}
   127  	if !data || err != nil {
   128  		return fi, err
   129  	}
   130  	versionID = fi.VersionID
   131  	if versionID == "" {
   132  		versionID = nullVersionID
   133  	}
   134  	fi.Data = inData.find(versionID)
   135  	if len(fi.Data) == 0 {
   136  		// PR #11758 used DataDir, preserve it
   137  		// for users who might have used master
   138  		// branch
   139  		fi.Data = inData.find(fi.DataDir)
   140  	}
   141  	return fi, nil
   142  }
   143  
   144  // getXLDiskLoc will return the pool/set/disk id if it can be located in the object layer.
   145  // Will return -1 for unknown values.
   146  func getXLDiskLoc(diskID string) (poolIdx, setIdx, diskIdx int) {
   147  	if api := newObjectLayerFn(); api != nil {
   148  		if globalIsErasureSD {
   149  			return 0, 0, 0
   150  		}
   151  		if ep, ok := api.(*erasureServerPools); ok {
   152  			if pool, set, disk, err := ep.getPoolAndSet(diskID); err == nil {
   153  				return pool, set, disk
   154  			}
   155  		}
   156  	}
   157  	return -1, -1, -1
   158  }
   159  
   160  // hashDeterministicString will return a deterministic hash for the map values.
   161  // Trivial collisions are avoided, but this is by no means a strong hash.
   162  func hashDeterministicString(m map[string]string) uint64 {
   163  	// Seed (random)
   164  	crc := uint64(0xc2b40bbac11a7295)
   165  	// Xor each value to make order independent
   166  	for k, v := range m {
   167  		// Separate key and value with an individual xor with a random number.
   168  		// Add values of each, so they cannot be trivially collided.
   169  		crc ^= (xxh3.HashString(k) ^ 0x4ee3bbaf7ab2506b) + (xxh3.HashString(v) ^ 0x8da4c8da66194257)
   170  	}
   171  	return crc
   172  }
   173  
   174  // hashDeterministicBytes will return a deterministic (weak) hash for the map values.
   175  // Trivial collisions are avoided, but this is by no means a strong hash.
   176  func hashDeterministicBytes(m map[string][]byte) uint64 {
   177  	crc := uint64(0x1bbc7e1dde654743)
   178  	for k, v := range m {
   179  		crc ^= (xxh3.HashString(k) ^ 0x4ee3bbaf7ab2506b) + (xxh3.Hash(v) ^ 0x8da4c8da66194257)
   180  	}
   181  	return crc
   182  }