@@ -18,6 +18,8 @@ import (
18
18
"context"
19
19
"crypto/sha256"
20
20
"encoding/hex"
21
+ "regexp"
22
+ "strconv"
21
23
"strings"
22
24
23
25
"github.com/klauspost/compress/zstd"
@@ -43,6 +45,20 @@ const (
43
45
streamBackupGlobalCheckpointPrefix = "v1/global_checkpoint"
44
46
)
45
47
48
+ // metaPattern is a regular expression used to match backup metadata filenames.
49
+ // The expected filename format is:
50
+ //
51
+ // {flushTs}-{minDefaultTs}-{minTs}-{maxTs}.meta
52
+ //
53
+ // where each part is a hexadecimal string (0-9, a-f, A-F).
54
+ // Example:
55
+ //
56
+ // 0000000000000001-0000000000003039-065CCFF1D8AC0000-065CCFF1D8AC0006.meta
57
+ //
58
+ // The pattern captures all four parts as separate groups.
59
+ // Leading zeros are necessary for the pattern to match.
60
+ var metaPattern = regexp .MustCompile (`^([0-9a-fA-F]{16})-([0-9a-fA-F]{16})-([0-9a-fA-F]{16})-([0-9a-fA-F]{16})$` )
61
+
46
62
func GetStreamBackupMetaPrefix () string {
47
63
return streamBackupMetaPrefix
48
64
}
@@ -356,11 +372,58 @@ func (*MetadataHelper) Marshal(meta *backuppb.Metadata) ([]byte, error) {
356
372
return meta .Marshal ()
357
373
}
358
374
375
+ func (m * MetadataHelper ) Close () {
376
+ if m .decoder != nil {
377
+ m .decoder .Close ()
378
+ }
379
+ if m .encryptionManager != nil {
380
+ m .encryptionManager .Close ()
381
+ }
382
+ }
383
+
384
+ func FilterPathByTs (path string , left , right uint64 ) string {
385
+ filename := strings .TrimSuffix (path , ".meta" )
386
+ filename = filename [strings .LastIndex (filename , "/" )+ 1 :]
387
+
388
+ if metaPattern .MatchString (filename ) {
389
+ matches := metaPattern .FindStringSubmatch (filename )
390
+ if len (matches ) < 5 {
391
+ log .Warn ("invalid meta file name format" , zap .String ("file" , path ))
392
+ // consider compatible with future file path change
393
+ return path
394
+ }
395
+
396
+ flushTs , _ := strconv .ParseUint (matches [1 ], 16 , 64 )
397
+ minDefaultTs , _ := strconv .ParseUint (matches [2 ], 16 , 64 )
398
+ minTs , _ := strconv .ParseUint (matches [3 ], 16 , 64 )
399
+ maxTs , _ := strconv .ParseUint (matches [4 ], 16 , 64 )
400
+
401
+ if minDefaultTs == 0 || minDefaultTs > minTs {
402
+ log .Warn ("minDefaultTs is not correct, fallback to minTs" ,
403
+ zap .String ("file" , path ),
404
+ zap .Uint64 ("flushTs" , flushTs ),
405
+ zap .Uint64 ("minTs" , minTs ),
406
+ zap .Uint64 ("minDefaultTs" , minDefaultTs ),
407
+ )
408
+ minDefaultTs = minTs
409
+ }
410
+
411
+ if right < minDefaultTs || maxTs < left {
412
+ return ""
413
+ }
414
+ }
415
+
416
+ // keep consistency with old behaviour
417
+ return path
418
+ }
419
+
359
420
// FastUnmarshalMetaData used a 128 worker pool to speed up
360
421
// read metadata content from external_storage.
361
422
func FastUnmarshalMetaData (
362
423
ctx context.Context ,
363
424
s storage.ExternalStorage ,
425
+ startTS uint64 ,
426
+ endTS uint64 ,
364
427
metaDataWorkerPoolSize uint ,
365
428
fn func (path string , rawMetaData []byte ) error ,
366
429
) error {
@@ -372,7 +435,15 @@ func FastUnmarshalMetaData(
372
435
if ! strings .HasSuffix (path , metaSuffix ) {
373
436
return nil
374
437
}
375
- readPath := path
438
+ readPath := FilterPathByTs (path , startTS , endTS )
439
+ if len (readPath ) == 0 {
440
+ log .Info ("skip download meta file out of range" ,
441
+ zap .String ("file" , path ),
442
+ zap .Uint64 ("startTs" , startTS ),
443
+ zap .Uint64 ("endTs" , endTS ),
444
+ )
445
+ return nil
446
+ }
376
447
pool .ApplyOnErrorGroup (eg , func () error {
377
448
b , err := s .ReadFile (ectx , readPath )
378
449
if err != nil {
0 commit comments