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 }