github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/relay/purger_test.go (about) 1 // Copyright 2019 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package relay 15 16 import ( 17 "bytes" 18 "context" 19 "os" 20 "path/filepath" 21 "strings" 22 "time" 23 24 . "github.com/pingcap/check" 25 "github.com/pingcap/tiflow/dm/config" 26 "github.com/pingcap/tiflow/dm/pb" 27 "github.com/pingcap/tiflow/dm/pkg/streamer" 28 "github.com/pingcap/tiflow/dm/pkg/utils" 29 ) 30 31 var _ = Suite(&testPurgerSuite{ 32 uuids: []string{ 33 "c6ae5afe-c7a3-11e8-a19d-0242ac130006.000001", 34 "e9540a0d-f16d-11e8-8cb7-0242ac130008.000002", 35 "195c342f-f46e-11e8-927c-0242ac150008.000003", 36 }, 37 relayFiles: [][]string{ 38 {"mysql-bin.000001", "mysql-bin.000002", "mysql-bin.000003"}, 39 {"mysql-bin.000001", "mysql-bin.000002", "mysql-bin.000003"}, 40 {"mysql-bin.000001", "mysql-bin.000002", "mysql-bin.000003"}, 41 }, 42 activeRelayLog: &streamer.RelayLogInfo{ 43 TaskName: fakeStrategyTaskName, 44 SubDir: "e9540a0d-f16d-11e8-8cb7-0242ac130008.000002", 45 SubDirSuffix: 2, 46 Filename: "mysql-bin.000003", // last in second sub dir 47 }, 48 }) 49 50 type testPurgerSuite struct { 51 uuids []string 52 relayFiles [][]string 53 activeRelayLog *streamer.RelayLogInfo 54 } 55 56 func (t *testPurgerSuite) EarliestActiveRelayLog() *streamer.RelayLogInfo { 57 return t.activeRelayLog 58 } 59 60 func (t *testPurgerSuite) TestPurgeManuallyInactive(c *C) { 61 // create relay log dir 62 baseDir := c.MkDir() 63 64 // prepare files and directories 65 relayDirsPath, relayFilesPath, _ := t.genRelayLogFiles(c, baseDir, -1, -1) 66 c.Assert(len(relayDirsPath), Equals, 3) 67 c.Assert(len(relayFilesPath), Equals, 3) 68 c.Assert(len(relayFilesPath[2]), Equals, 3) 69 70 err := t.genUUIDIndexFile(baseDir) 71 c.Assert(err, IsNil) 72 73 cfg := config.PurgeConfig{ 74 Interval: 0, // disable automatically 75 } 76 77 purger := NewPurger(cfg, baseDir, []Operator{t}, nil) 78 79 req := &pb.PurgeRelayRequest{ 80 Inactive: true, 81 } 82 err = purger.Do(context.Background(), req) 83 c.Assert(err, IsNil) 84 85 c.Assert(utils.IsDirExists(relayDirsPath[0]), IsFalse) 86 c.Assert(utils.IsDirExists(relayDirsPath[1]), IsTrue) 87 c.Assert(utils.IsDirExists(relayDirsPath[2]), IsTrue) 88 89 c.Assert(utils.IsFileExists(relayFilesPath[1][0]), IsFalse) 90 c.Assert(utils.IsFileExists(relayFilesPath[1][1]), IsFalse) 91 c.Assert(utils.IsFileExists(relayFilesPath[1][2]), IsTrue) 92 for _, fp := range relayFilesPath[2] { 93 c.Assert(utils.IsFileExists(fp), IsTrue) 94 } 95 } 96 97 func (t *testPurgerSuite) TestPurgeManuallyTime(c *C) { 98 // create relay log dir 99 baseDir := c.MkDir() 100 101 // prepare files and directories 102 relayDirsPath, relayFilesPath, safeTime := t.genRelayLogFiles(c, baseDir, 1, 0) 103 c.Assert(len(relayDirsPath), Equals, 3) 104 c.Assert(len(relayFilesPath), Equals, 3) 105 c.Assert(len(relayFilesPath[2]), Equals, 3) 106 107 err := t.genUUIDIndexFile(baseDir) 108 c.Assert(err, IsNil) 109 110 cfg := config.PurgeConfig{ 111 Interval: 0, // disable automatically 112 } 113 114 purger := NewPurger(cfg, baseDir, []Operator{t}, nil) 115 116 req := &pb.PurgeRelayRequest{ 117 Time: safeTime.Unix(), 118 } 119 err = purger.Do(context.Background(), req) 120 c.Assert(err, IsNil) 121 122 c.Assert(utils.IsDirExists(relayDirsPath[0]), IsFalse) 123 c.Assert(utils.IsDirExists(relayDirsPath[1]), IsTrue) 124 c.Assert(utils.IsDirExists(relayDirsPath[2]), IsTrue) 125 126 c.Assert(utils.IsFileExists(relayFilesPath[1][0]), IsFalse) 127 c.Assert(utils.IsFileExists(relayFilesPath[1][1]), IsTrue) 128 c.Assert(utils.IsFileExists(relayFilesPath[1][2]), IsTrue) 129 for _, fp := range relayFilesPath[2] { 130 c.Assert(utils.IsFileExists(fp), IsTrue) 131 } 132 } 133 134 func (t *testPurgerSuite) TestPurgeManuallyFilename(c *C) { 135 // create relay log dir 136 baseDir := c.MkDir() 137 138 // prepare files and directories 139 relayDirsPath, relayFilesPath, _ := t.genRelayLogFiles(c, baseDir, -1, -1) 140 c.Assert(len(relayDirsPath), Equals, 3) 141 c.Assert(len(relayFilesPath), Equals, 3) 142 c.Assert(len(relayFilesPath[2]), Equals, 3) 143 144 err := t.genUUIDIndexFile(baseDir) 145 c.Assert(err, IsNil) 146 147 cfg := config.PurgeConfig{ 148 Interval: 0, // disable automatically 149 } 150 151 purger := NewPurger(cfg, baseDir, []Operator{t}, nil) 152 153 req := &pb.PurgeRelayRequest{ 154 Filename: t.relayFiles[0][2], 155 SubDir: t.uuids[0], 156 } 157 err = purger.Do(context.Background(), req) 158 c.Assert(err, IsNil) 159 160 c.Assert(utils.IsDirExists(relayDirsPath[0]), IsTrue) 161 c.Assert(utils.IsDirExists(relayDirsPath[1]), IsTrue) 162 c.Assert(utils.IsDirExists(relayDirsPath[2]), IsTrue) 163 164 c.Assert(utils.IsFileExists(relayFilesPath[0][0]), IsFalse) 165 c.Assert(utils.IsFileExists(relayFilesPath[0][1]), IsFalse) 166 c.Assert(utils.IsFileExists(relayFilesPath[0][2]), IsTrue) 167 for _, fp := range relayFilesPath[1] { 168 c.Assert(utils.IsFileExists(fp), IsTrue) 169 } 170 for _, fp := range relayFilesPath[2] { 171 c.Assert(utils.IsFileExists(fp), IsTrue) 172 } 173 } 174 175 func (t *testPurgerSuite) TestPurgeAutomaticallyTime(c *C) { 176 // create relay log dir 177 baseDir := c.MkDir() 178 179 // prepare files and directories 180 relayDirsPath, relayFilesPath, _ := t.genRelayLogFiles(c, baseDir, -1, -1) 181 c.Assert(len(relayDirsPath), Equals, 3) 182 c.Assert(len(relayFilesPath), Equals, 3) 183 c.Assert(len(relayFilesPath[2]), Equals, 3) 184 185 err := t.genUUIDIndexFile(baseDir) 186 c.Assert(err, IsNil) 187 188 cfg := config.PurgeConfig{ 189 Interval: 1, // enable automatically 190 Expires: 1, 191 } 192 193 // change files' modification time 194 aTime := time.Now().Add(time.Duration(-cfg.Expires*3) * time.Hour) 195 mTime := time.Now().Add(time.Duration(-cfg.Expires*2) * time.Hour) 196 for _, fps := range relayFilesPath { 197 for _, fp := range fps { 198 err = os.Chtimes(fp, aTime, mTime) 199 c.Assert(err, IsNil) 200 } 201 } 202 203 purger := NewPurger(cfg, baseDir, []Operator{t}, nil) 204 purger.Start() 205 time.Sleep(2 * time.Second) // sleep enough time to purge all inactive relay log files 206 purger.Close() 207 208 c.Assert(utils.IsDirExists(relayDirsPath[0]), IsFalse) 209 c.Assert(utils.IsDirExists(relayDirsPath[1]), IsTrue) 210 c.Assert(utils.IsDirExists(relayDirsPath[2]), IsTrue) 211 212 c.Assert(utils.IsFileExists(relayFilesPath[1][0]), IsFalse) 213 c.Assert(utils.IsFileExists(relayFilesPath[1][1]), IsFalse) 214 c.Assert(utils.IsFileExists(relayFilesPath[1][2]), IsTrue) 215 for _, fp := range relayFilesPath[2] { 216 c.Assert(utils.IsFileExists(fp), IsTrue) 217 } 218 } 219 220 func (t *testPurgerSuite) TestPurgeAutomaticallySpace(c *C) { 221 // create relay log dir 222 baseDir := c.MkDir() 223 224 // prepare files and directories 225 relayDirsPath, relayFilesPath, _ := t.genRelayLogFiles(c, baseDir, -1, -1) 226 c.Assert(len(relayDirsPath), Equals, 3) 227 c.Assert(len(relayFilesPath), Equals, 3) 228 c.Assert(len(relayFilesPath[2]), Equals, 3) 229 230 err := t.genUUIDIndexFile(baseDir) 231 c.Assert(err, IsNil) 232 233 storageSize, err := utils.GetStorageSize(baseDir) 234 c.Assert(err, IsNil) 235 236 cfg := config.PurgeConfig{ 237 Interval: 1, // enable automatically 238 RemainSpace: int64(storageSize.Available)/1024/1024/1024 + 1024, // always trigger purge 239 } 240 241 purger := NewPurger(cfg, baseDir, []Operator{t}, nil) 242 purger.Start() 243 time.Sleep(2 * time.Second) // sleep enough time to purge all inactive relay log files 244 purger.Close() 245 246 c.Assert(utils.IsDirExists(relayDirsPath[0]), IsFalse) 247 c.Assert(utils.IsDirExists(relayDirsPath[1]), IsTrue) 248 c.Assert(utils.IsDirExists(relayDirsPath[2]), IsTrue) 249 250 c.Assert(utils.IsFileExists(relayFilesPath[1][0]), IsFalse) 251 c.Assert(utils.IsFileExists(relayFilesPath[1][1]), IsFalse) 252 c.Assert(utils.IsFileExists(relayFilesPath[1][2]), IsTrue) 253 for _, fp := range relayFilesPath[2] { 254 c.Assert(utils.IsFileExists(fp), IsTrue) 255 } 256 } 257 258 func (t *testPurgerSuite) genRelayLogFiles(c *C, baseDir string, safeTimeIdxI, safeTimeIdxJ int) ([]string, [][]string, time.Time) { 259 var ( 260 relayDirsPath = make([]string, 0, 3) 261 relayFilesPath = make([][]string, 0, 3) 262 safeTime = time.Unix(0, 0) 263 ) 264 265 for _, uuid := range t.uuids { 266 dir := filepath.Join(baseDir, uuid) 267 err := os.Mkdir(dir, 0o700) 268 c.Assert(err, IsNil) 269 relayDirsPath = append(relayDirsPath, dir) 270 } 271 272 // create relay log files 273 for i, uuid := range t.uuids { 274 dir := filepath.Join(baseDir, uuid) 275 relayFilesPath = append(relayFilesPath, []string{}) 276 for j, fn := range t.relayFiles[i] { 277 fp := filepath.Join(dir, fn) 278 err2 := os.WriteFile(fp, []byte("meaningless file content"), 0o644) 279 c.Assert(err2, IsNil) 280 relayFilesPath[i] = append(relayFilesPath[i], fp) 281 282 if i == safeTimeIdxI && j == safeTimeIdxJ { 283 time.Sleep(time.Second) 284 safeTime = time.Now() 285 time.Sleep(time.Second) 286 } 287 } 288 } 289 290 return relayDirsPath, relayFilesPath, safeTime 291 } 292 293 func (t *testPurgerSuite) genUUIDIndexFile(baseDir string) error { 294 fp := filepath.Join(baseDir, utils.UUIDIndexFilename) 295 296 var buf bytes.Buffer 297 for _, uuid := range t.uuids { 298 buf.WriteString(uuid) 299 buf.WriteString("\n") 300 } 301 302 return utils.WriteFileAtomic(fp, buf.Bytes(), 0o644) 303 } 304 305 type fakeInterceptor struct { 306 msg string 307 } 308 309 func newFakeInterceptor() *fakeInterceptor { 310 return &fakeInterceptor{ 311 msg: "forbid purge by fake interceptor", 312 } 313 } 314 315 func (i *fakeInterceptor) ForbidPurge() (bool, string) { 316 return true, i.msg 317 } 318 319 func (t *testPurgerSuite) TestPurgerInterceptor(c *C) { 320 cfg := config.PurgeConfig{} 321 interceptor := newFakeInterceptor() 322 323 purger := NewPurger(cfg, "", []Operator{t}, []PurgeInterceptor{interceptor}) 324 325 req := &pb.PurgeRelayRequest{ 326 Inactive: true, 327 } 328 err := purger.Do(context.Background(), req) 329 c.Assert(err, NotNil) 330 c.Assert(strings.Contains(err.Error(), interceptor.msg), IsTrue) 331 }