github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/erasure-sets_test.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 "context" 22 "os" 23 "path/filepath" 24 "testing" 25 26 "github.com/google/uuid" 27 ) 28 29 var testUUID = uuid.MustParse("f5c58c61-7175-4018-ab5e-a94fe9c2de4e") 30 31 func BenchmarkCrcHash(b *testing.B) { 32 cases := []struct { 33 key int 34 }{ 35 {16}, 36 {64}, 37 {128}, 38 {256}, 39 {512}, 40 {1024}, 41 } 42 for _, testCase := range cases { 43 testCase := testCase 44 key := randString(testCase.key) 45 b.Run("", func(b *testing.B) { 46 b.SetBytes(1024) 47 b.ReportAllocs() 48 b.ResetTimer() 49 for i := 0; i < b.N; i++ { 50 crcHashMod(key, 16) 51 } 52 }) 53 } 54 } 55 56 func BenchmarkSipHash(b *testing.B) { 57 cases := []struct { 58 key int 59 }{ 60 {16}, 61 {64}, 62 {128}, 63 {256}, 64 {512}, 65 {1024}, 66 } 67 for _, testCase := range cases { 68 testCase := testCase 69 key := randString(testCase.key) 70 b.Run("", func(b *testing.B) { 71 b.SetBytes(1024) 72 b.ReportAllocs() 73 b.ResetTimer() 74 for i := 0; i < b.N; i++ { 75 sipHashMod(key, 16, testUUID) 76 } 77 }) 78 } 79 } 80 81 // TestSipHashMod - test sip hash. 82 func TestSipHashMod(t *testing.T) { 83 testCases := []struct { 84 objectName string 85 sipHash int 86 }{ 87 // cases which should pass the test. 88 // passing in valid object name. 89 {"object", 37}, 90 {"The Shining Script <v1>.pdf", 38}, 91 {"Cost Benefit Analysis (2009-2010).pptx", 59}, 92 {"117Gn8rfHL2ACARPAhaFd0AGzic9pUbIA/5OCn5A", 35}, 93 {"SHØRT", 49}, 94 {"There are far too many object names, and far too few bucket names!", 8}, 95 {"a/b/c/", 159}, 96 {"/a/b/c", 96}, 97 {string([]byte{0xff, 0xfe, 0xfd}), 147}, 98 } 99 100 // Tests hashing order to be consistent. 101 for i, testCase := range testCases { 102 if sipHashElement := hashKey("SIPMOD", testCase.objectName, 200, testUUID); sipHashElement != testCase.sipHash { 103 t.Errorf("Test case %d: Expected \"%v\" but failed \"%v\"", i+1, testCase.sipHash, sipHashElement) 104 } 105 } 106 107 if sipHashElement := hashKey("SIPMOD", "This will fail", -1, testUUID); sipHashElement != -1 { 108 t.Errorf("Test: Expected \"-1\" but got \"%v\"", sipHashElement) 109 } 110 111 if sipHashElement := hashKey("SIPMOD", "This will fail", 0, testUUID); sipHashElement != -1 { 112 t.Errorf("Test: Expected \"-1\" but got \"%v\"", sipHashElement) 113 } 114 115 if sipHashElement := hashKey("UNKNOWN", "This will fail", 0, testUUID); sipHashElement != -1 { 116 t.Errorf("Test: Expected \"-1\" but got \"%v\"", sipHashElement) 117 } 118 } 119 120 // TestCrcHashMod - test crc hash. 121 func TestCrcHashMod(t *testing.T) { 122 testCases := []struct { 123 objectName string 124 crcHash int 125 }{ 126 // cases which should pass the test. 127 // passing in valid object name. 128 {"object", 28}, 129 {"The Shining Script <v1>.pdf", 142}, 130 {"Cost Benefit Analysis (2009-2010).pptx", 133}, 131 {"117Gn8rfHL2ACARPAhaFd0AGzic9pUbIA/5OCn5A", 185}, 132 {"SHØRT", 97}, 133 {"There are far too many object names, and far too few bucket names!", 101}, 134 {"a/b/c/", 193}, 135 {"/a/b/c", 116}, 136 {string([]byte{0xff, 0xfe, 0xfd}), 61}, 137 } 138 139 // Tests hashing order to be consistent. 140 for i, testCase := range testCases { 141 if crcHashElement := hashKey("CRCMOD", testCase.objectName, 200, testUUID); crcHashElement != testCase.crcHash { 142 t.Errorf("Test case %d: Expected \"%v\" but failed \"%v\"", i+1, testCase.crcHash, crcHashElement) 143 } 144 } 145 146 if crcHashElement := hashKey("CRCMOD", "This will fail", -1, testUUID); crcHashElement != -1 { 147 t.Errorf("Test: Expected \"-1\" but got \"%v\"", crcHashElement) 148 } 149 150 if crcHashElement := hashKey("CRCMOD", "This will fail", 0, testUUID); crcHashElement != -1 { 151 t.Errorf("Test: Expected \"-1\" but got \"%v\"", crcHashElement) 152 } 153 154 if crcHashElement := hashKey("UNKNOWN", "This will fail", 0, testUUID); crcHashElement != -1 { 155 t.Errorf("Test: Expected \"-1\" but got \"%v\"", crcHashElement) 156 } 157 } 158 159 // TestNewErasure - tests initialization of all input disks 160 // and constructs a valid `Erasure` object 161 func TestNewErasureSets(t *testing.T) { 162 ctx, cancel := context.WithCancel(context.Background()) 163 defer cancel() 164 165 nDisks := 16 // Maximum disks. 166 var erasureDisks []string 167 for i := 0; i < nDisks; i++ { 168 // Do not attempt to create this path, the test validates 169 // so that newErasureSets initializes non existing paths 170 // and successfully returns initialized object layer. 171 disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix()) 172 erasureDisks = append(erasureDisks, disk) 173 defer os.RemoveAll(disk) 174 } 175 176 endpoints := mustGetNewEndpoints(0, 16, erasureDisks...) 177 _, _, err := waitForFormatErasure(true, endpoints, 1, 0, 16, "") 178 if err != errInvalidArgument { 179 t.Fatalf("Expecting error, got %s", err) 180 } 181 182 _, _, err = waitForFormatErasure(true, nil, 1, 1, 16, "") 183 if err != errInvalidArgument { 184 t.Fatalf("Expecting error, got %s", err) 185 } 186 187 // Initializes all erasure disks 188 storageDisks, format, err := waitForFormatErasure(true, endpoints, 1, 1, 16, "") 189 if err != nil { 190 t.Fatalf("Unable to format drives for erasure, %s", err) 191 } 192 193 ep := PoolEndpoints{Endpoints: endpoints} 194 195 parity, err := ecDrivesNoConfig(16) 196 if err != nil { 197 t.Fatalf("Unexpected error during EC drive config: %v", err) 198 } 199 if _, err := newErasureSets(ctx, ep, storageDisks, format, parity, 0); err != nil { 200 t.Fatalf("Unable to initialize erasure") 201 } 202 } 203 204 // TestHashedLayer - tests the hashed layer which will be returned 205 // consistently for a given object name. 206 func TestHashedLayer(t *testing.T) { 207 // Test distribution with 16 sets. 208 var objs [16]*erasureObjects 209 for i := range objs { 210 objs[i] = &erasureObjects{} 211 } 212 213 sets := &erasureSets{sets: objs[:], distributionAlgo: "CRCMOD"} 214 215 testCases := []struct { 216 objectName string 217 expectedObj *erasureObjects 218 }{ 219 // cases which should pass the test. 220 // passing in valid object name. 221 {"object", objs[12]}, 222 {"The Shining Script <v1>.pdf", objs[14]}, 223 {"Cost Benefit Analysis (2009-2010).pptx", objs[13]}, 224 {"117Gn8rfHL2ACARPAhaFd0AGzic9pUbIA/5OCn5A", objs[1]}, 225 {"SHØRT", objs[9]}, 226 {"There are far too many object names, and far too few bucket names!", objs[13]}, 227 {"a/b/c/", objs[1]}, 228 {"/a/b/c", objs[4]}, 229 {string([]byte{0xff, 0xfe, 0xfd}), objs[13]}, 230 } 231 232 // Tests hashing order to be consistent. 233 for i, testCase := range testCases { 234 gotObj := sets.getHashedSet(testCase.objectName) 235 if gotObj != testCase.expectedObj { 236 t.Errorf("Test case %d: Expected \"%#v\" but failed \"%#v\"", i+1, testCase.expectedObj, gotObj) 237 } 238 } 239 }