github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/core/lom_xattr_test.go (about) 1 // Package core_test provides tests for cluster package 2 /* 3 * Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package core_test 6 7 import ( 8 "os" 9 10 "github.com/NVIDIA/aistore/api/apc" 11 "github.com/NVIDIA/aistore/cmn" 12 "github.com/NVIDIA/aistore/cmn/cos" 13 "github.com/NVIDIA/aistore/core" 14 "github.com/NVIDIA/aistore/core/meta" 15 "github.com/NVIDIA/aistore/core/mock" 16 "github.com/NVIDIA/aistore/fs" 17 . "github.com/onsi/ginkgo/v2" 18 . "github.com/onsi/gomega" 19 ) 20 21 var _ = Describe("LOM Xattributes", func() { 22 const ( 23 tmpDir = "/tmp/lom_xattr_test" 24 xattrMpath = tmpDir + "/xattr" 25 copyMpath = tmpDir + "/copy" 26 27 bucketLocal = "LOM_TEST_Local" 28 bucketCached = "LOM_TEST_Cached" 29 ) 30 31 localBck := cmn.Bck{Name: bucketLocal, Provider: apc.AIS, Ns: cmn.NsGlobal} 32 cachedBck := cmn.Bck{Name: bucketCached, Provider: apc.AIS, Ns: cmn.NsGlobal} 33 34 fs.CSM.Reg(fs.ObjectType, &fs.ObjectContentResolver{}, true) 35 fs.CSM.Reg(fs.WorkfileType, &fs.WorkfileContentResolver{}, true) 36 37 var ( 38 copyMpathInfo *fs.Mountpath 39 mix = fs.Mountpath{Path: xattrMpath} 40 bmdMock = mock.NewBaseBownerMock( 41 meta.NewBck( 42 bucketLocal, apc.AIS, cmn.NsGlobal, 43 &cmn.Bprops{Cksum: cmn.CksumConf{Type: cos.ChecksumXXHash}, BID: 201}, 44 ), 45 meta.NewBck( 46 bucketCached, apc.AIS, cmn.NsGlobal, 47 &cmn.Bprops{ 48 Cksum: cmn.CksumConf{Type: cos.ChecksumXXHash}, 49 WritePolicy: cmn.WritePolicyConf{Data: apc.WriteImmediate, MD: apc.WriteNever}, 50 BID: 202, 51 }, 52 ), 53 ) 54 ) 55 56 BeforeEach(func() { 57 _ = cos.CreateDir(xattrMpath) 58 _ = cos.CreateDir(copyMpath) 59 60 _, _ = fs.Add(xattrMpath, "daeID") 61 _, _ = fs.Add(copyMpath, "daeID") 62 63 available := fs.GetAvail() 64 copyMpathInfo = available[copyMpath] 65 66 _ = mock.NewTarget(bmdMock) 67 }) 68 69 AfterEach(func() { 70 _, _ = fs.Remove(xattrMpath) 71 _, _ = fs.Remove(copyMpath) 72 _ = os.RemoveAll(tmpDir) 73 }) 74 75 Describe("xattrs", func() { 76 var ( 77 testFileSize = 456 78 testObjectName = "xattr-foldr/test-obj.ext" 79 80 // Bucket needs to have checksum enabled 81 localFQN = mix.MakePathFQN(&localBck, fs.ObjectType, testObjectName+".qqq") 82 cachedFQN = mix.MakePathFQN(&cachedBck, fs.ObjectType, testObjectName) 83 84 fqns []string 85 ) 86 87 BeforeEach(func() { 88 fqns = []string{ 89 copyMpathInfo.MakePathFQN(&localBck, fs.ObjectType, "copy/111/fqn"), 90 copyMpathInfo.MakePathFQN(&localBck, fs.ObjectType, "other/copy/fqn"), 91 } 92 93 // NOTE: 94 // the test creates copies; there's a built-in assumption that `mi` will be 95 // the HRW mountpath, 96 // while `mi2` will not (and, therefore, can be used to place the copy). 97 // Ultimately, this depends on the specific HRW hash; adding 98 // Expect(lom.IsHRW()).To(Be...)) to catch that sooner. 99 100 for _, fqn := range fqns { 101 lom := filePut(fqn, testFileSize) 102 Expect(lom.IsHRW()).To(BeFalse()) 103 } 104 }) 105 106 Describe("Persist", func() { 107 It("should save correct meta to disk", func() { 108 lom := filePut(localFQN, testFileSize) 109 Expect(lom.IsHRW()).To(BeTrue()) 110 lom.Lock(true) 111 defer lom.Unlock(true) 112 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 113 lom.SetVersion("dummy_version") 114 lom.SetCustomMD(cos.StrKVs{ 115 cmn.SourceObjMD: apc.GCP, 116 cmn.ETag: "etag", 117 cmn.CRC32CObjMD: "crc32", 118 }) 119 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 120 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 121 Expect(persist(lom)).NotTo(HaveOccurred()) 122 123 b, err := fs.GetXattr(localFQN, core.XattrLOM) 124 Expect(b).ToNot(BeEmpty()) 125 Expect(err).NotTo(HaveOccurred()) 126 127 hrwLom := &core.LOM{ObjName: testObjectName} 128 Expect(hrwLom.InitBck(&localBck)).NotTo(HaveOccurred()) 129 hrwLom.UncacheUnless() 130 131 newLom := NewBasicLom(localFQN) 132 err = newLom.Load(false, true) 133 Expect(err).NotTo(HaveOccurred()) 134 Expect(lom.Checksum()).To(BeEquivalentTo(newLom.Checksum())) 135 Expect(lom.Version()).To(BeEquivalentTo(newLom.Version())) 136 Expect(lom.GetCopies()).To(HaveLen(3)) 137 Expect(lom.GetCopies()).To(BeEquivalentTo(newLom.GetCopies())) 138 Expect(lom.GetCustomMD()).To(HaveLen(3)) 139 Expect(lom.GetCustomMD()).To(BeEquivalentTo(newLom.GetCustomMD())) 140 }) 141 142 It("should _not_ save meta to disk", func() { 143 lom := filePut(cachedFQN, testFileSize) 144 Expect(lom.IsHRW()).To(BeTrue()) 145 lom.Lock(true) 146 defer lom.Unlock(true) 147 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 148 lom.SetVersion("dummy_version") 149 Expect(persist(lom)).NotTo(HaveOccurred()) 150 151 lom.SetCustomMD(cos.StrKVs{ 152 cmn.SourceObjMD: apc.GCP, 153 cmn.ETag: "etag", 154 cmn.CRC32CObjMD: "crc32", 155 }) 156 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 157 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 158 Expect(persist(lom)).NotTo(HaveOccurred()) 159 160 b, err := fs.GetXattr(cachedFQN, core.XattrLOM) 161 Expect(b).To(BeEmpty()) 162 Expect(err).To(HaveOccurred()) 163 164 hrwLom := &core.LOM{ObjName: testObjectName} 165 Expect(hrwLom.InitBck(&localBck)).NotTo(HaveOccurred()) 166 hrwLom.UncacheUnless() 167 168 ver := lom.Version() 169 lom.UncacheUnless() 170 171 newLom := NewBasicLom(cachedFQN) 172 err = newLom.Load(false, true) 173 Expect(err).NotTo(HaveOccurred()) 174 Expect(lom.Checksum()).To(BeEquivalentTo(newLom.Checksum())) 175 Expect(ver).To(BeEquivalentTo(newLom.Version())) 176 Expect(lom.GetCopies()).To(HaveLen(3)) 177 Expect(lom.GetCopies()).To(BeEquivalentTo(newLom.GetCopies())) 178 Expect(lom.GetCustomMD()).To(HaveLen(3)) 179 Expect(lom.GetCustomMD()).To(BeEquivalentTo(newLom.GetCustomMD())) 180 }) 181 182 It("should copy object with meta in memory", func() { 183 lom := filePut(cachedFQN, testFileSize) 184 lom.Lock(true) 185 defer lom.Unlock(true) 186 cksumHash, err := lom.ComputeCksum(lom.CksumType()) 187 Expect(err).NotTo(HaveOccurred()) 188 lom.SetCksum(cksumHash.Clone()) 189 lom.SetVersion("first_version") 190 Expect(persist(lom)).NotTo(HaveOccurred()) 191 192 lom.SetCustomMD(cos.StrKVs{ 193 cmn.SourceObjMD: apc.GCP, 194 cmn.ETag: "etag", 195 cmn.CRC32CObjMD: "crc32", 196 }) 197 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 198 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 199 lom.SetVersion("second_version") 200 Expect(persist(lom)).NotTo(HaveOccurred()) 201 202 b, err := fs.GetXattr(cachedFQN, core.XattrLOM) 203 Expect(b).To(BeEmpty()) 204 Expect(err).To(HaveOccurred()) 205 206 hrwLom := &core.LOM{ObjName: testObjectName} 207 Expect(hrwLom.InitBck(&localBck)).NotTo(HaveOccurred()) 208 hrwLom.UncacheUnless() 209 210 lom.UncacheUnless() 211 lom.Load(true, false) 212 Expect(lom.Version()).To(BeEquivalentTo("second_version")) 213 Expect(lom.GetCopies()).To(HaveLen(3)) 214 215 buf := make([]byte, cos.KiB) 216 newLom, err := lom.Copy2FQN(cachedFQN+"-copy", buf) 217 Expect(err).NotTo(HaveOccurred()) 218 219 err = newLom.Load(false, false) 220 Expect(err).NotTo(HaveOccurred()) 221 Expect(lom.Checksum()).To(BeEquivalentTo(newLom.Checksum())) 222 Expect(lom.Version()).To(BeEquivalentTo(newLom.Version())) 223 Expect(newLom.GetCustomMD()).To(HaveLen(3)) 224 Expect(lom.GetCustomMD()).To(BeEquivalentTo(newLom.GetCustomMD())) 225 }) 226 227 It("should override old values", func() { 228 lom := filePut(localFQN, testFileSize) 229 lom.Lock(true) 230 defer lom.Unlock(true) 231 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 232 lom.SetVersion("dummy_version1") 233 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 234 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 235 236 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 237 lom.SetVersion("dummy_version2") 238 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 239 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 240 Expect(persist(lom)).NotTo(HaveOccurred()) 241 242 b, err := fs.GetXattr(localFQN, core.XattrLOM) 243 Expect(b).ToNot(BeEmpty()) 244 Expect(err).NotTo(HaveOccurred()) 245 246 hrwLom := &core.LOM{ObjName: testObjectName} 247 Expect(hrwLom.InitBck(&localBck)).NotTo(HaveOccurred()) 248 hrwLom.UncacheUnless() 249 250 newLom := NewBasicLom(localFQN) 251 err = newLom.Load(false, true) 252 Expect(err).NotTo(HaveOccurred()) 253 Expect(lom.Checksum()).To(BeEquivalentTo(newLom.Checksum())) 254 Expect(lom.Version()).To(BeEquivalentTo(newLom.Version())) 255 Expect(lom.GetCopies()).To(HaveLen(3)) 256 Expect(lom.GetCopies()).To(BeEquivalentTo(newLom.GetCopies())) 257 }) 258 }) 259 260 Describe("LoadMetaFromFS", func() { 261 It("should read fresh meta from fs", func() { 262 createTestFile(localFQN, testFileSize) 263 lom1 := NewBasicLom(localFQN) 264 lom2 := NewBasicLom(localFQN) 265 lom1.Lock(true) 266 defer lom1.Unlock(true) 267 lom1.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 268 lom1.SetVersion("dummy_version") 269 Expect(lom1.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 270 Expect(lom1.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 271 Expect(persist(lom1)).NotTo(HaveOccurred()) 272 273 err := lom2.LoadMetaFromFS() 274 Expect(err).NotTo(HaveOccurred()) 275 276 Expect(lom1.Checksum()).To(BeEquivalentTo(lom2.Checksum())) 277 Expect(lom1.Version(true)).To(BeEquivalentTo(lom2.Version(true))) 278 Expect(lom1.GetCopies()).To(HaveLen(3)) 279 Expect(lom1.GetCopies()).To(BeEquivalentTo(lom2.GetCopies())) 280 }) 281 282 Describe("error cases", func() { 283 var lom *core.LOM 284 285 BeforeEach(func() { 286 createTestFile(localFQN, testFileSize) 287 lom = NewBasicLom(localFQN) 288 lom.Lock(true) 289 defer lom.Unlock(true) 290 lom.SetCksum(cos.NewCksum(cos.ChecksumXXHash, "test_checksum")) 291 lom.SetVersion("dummy_version") 292 Expect(lom.AddCopy(fqns[0], copyMpathInfo)).NotTo(HaveOccurred()) 293 Expect(lom.AddCopy(fqns[1], copyMpathInfo)).NotTo(HaveOccurred()) 294 Expect(persist(lom)).NotTo(HaveOccurred()) 295 }) 296 297 It("should fail when checksum does not match", func() { 298 b, err := fs.GetXattr(localFQN, core.XattrLOM) 299 Expect(err).NotTo(HaveOccurred()) 300 301 b[2]++ // changing first byte of meta checksum 302 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 303 err = lom.LoadMetaFromFS() 304 Expect(err.Error()).To(ContainSubstring("BAD META CHECKSUM")) 305 }) 306 307 It("should fail when checksum type is invalid", func() { 308 b, err := fs.GetXattr(localFQN, core.XattrLOM) 309 Expect(err).NotTo(HaveOccurred()) 310 311 b[1] = 200 // corrupting checksum type 312 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 313 err = lom.LoadMetaFromFS() 314 Expect(err).To(MatchError("invalid lmeta: unknown checksum 200")) 315 316 b, err = fs.GetXattr(localFQN, core.XattrLOM) 317 Expect(err).NotTo(HaveOccurred()) 318 319 b[1] = 0 // corrupting checksum type 320 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 321 err = lom.LoadMetaFromFS() 322 Expect(err).To(MatchError("invalid lmeta: unknown checksum 0")) 323 }) 324 325 It("should fail when metadata version is invalid", func() { 326 b, err := fs.GetXattr(localFQN, core.XattrLOM) 327 Expect(err).NotTo(HaveOccurred()) 328 329 b[0] = 128 // corrupting metadata version 330 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 331 err = lom.LoadMetaFromFS() 332 Expect(err).To(MatchError("invalid lmeta: unknown version 128")) 333 334 b[0] = 0 // corrupting metadata version 335 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 336 err = lom.LoadMetaFromFS() 337 Expect(err).To(MatchError("invalid lmeta: unknown version 0")) 338 }) 339 340 It("should fail when metadata is too short", func() { 341 Expect(fs.SetXattr(localFQN, core.XattrLOM, []byte{1})).NotTo(HaveOccurred()) 342 err := lom.LoadMetaFromFS() 343 Expect(err).To(HaveOccurred()) 344 345 Expect(fs.SetXattr(localFQN, core.XattrLOM, []byte{1, 1, 2})).NotTo(HaveOccurred()) 346 err = lom.LoadMetaFromFS() 347 Expect(err).To(MatchError("invalid lmeta: too short (3)")) 348 }) 349 350 It("should fail when meta is corrupted", func() { 351 // This test is supposed to end with LoadMetaFromFS error 352 // not with nil pointer exception / panic 353 b, err := fs.GetXattr(localFQN, core.XattrLOM) 354 Expect(err).NotTo(HaveOccurred()) 355 copy(b[40:], "1321wr") 356 Expect(fs.SetXattr(localFQN, core.XattrLOM, b)).NotTo(HaveOccurred()) 357 358 err = lom.LoadMetaFromFS() 359 Expect(err.Error()).To(ContainSubstring("BAD META CHECKSUM")) 360 }) 361 }) 362 }) 363 }) 364 })