github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/nbs/gc_copier.go (about) 1 // Copyright 2020 Dolthub, 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package nbs 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 22 "github.com/dolthub/dolt/go/store/hash" 23 ) 24 25 type gcErrAccum map[string]error 26 27 var _ error = gcErrAccum{} 28 29 func (ea gcErrAccum) add(path string, err error) { 30 ea[path] = err 31 } 32 33 func (ea gcErrAccum) isEmpty() bool { 34 return len(ea) == 0 35 } 36 37 func (ea gcErrAccum) Error() string { 38 var sb strings.Builder 39 sb.WriteString("error garbage collecting the following files:") 40 for filePath, err := range ea { 41 sb.WriteString(fmt.Sprintf("\t%s: %s", filePath, err.Error())) 42 } 43 return sb.String() 44 } 45 46 type gcCopier struct { 47 writer *CmpChunkTableWriter 48 } 49 50 func newGarbageCollectionCopier() (*gcCopier, error) { 51 writer, err := NewCmpChunkTableWriter("") 52 if err != nil { 53 return nil, err 54 } 55 return &gcCopier{writer}, nil 56 } 57 58 func (gcc *gcCopier) addChunk(ctx context.Context, c CompressedChunk) error { 59 return gcc.writer.AddCmpChunk(c) 60 } 61 62 func (gcc *gcCopier) copyTablesToDir(ctx context.Context, tfp tableFilePersister) (ts []tableSpec, err error) { 63 var filename string 64 filename, err = gcc.writer.Finish() 65 if err != nil { 66 return nil, err 67 } 68 69 if gcc.writer.ChunkCount() == 0 { 70 return []tableSpec{}, nil 71 } 72 73 defer func() { 74 _ = gcc.writer.Remove() 75 }() 76 77 addr, ok := hash.MaybeParse(filename) 78 if !ok { 79 return nil, fmt.Errorf("invalid filename: %s", filename) 80 } 81 82 exists, err := tfp.Exists(ctx, addr, uint32(gcc.writer.ChunkCount()), nil) 83 if err != nil { 84 return nil, err 85 } 86 87 if exists { 88 return []tableSpec{ 89 { 90 name: addr, 91 chunkCount: uint32(gcc.writer.ChunkCount()), 92 }, 93 }, nil 94 } 95 96 // Attempt to rename the file to the destination if we are working with a fsTablePersister... 97 if mover, ok := tfp.(movingTableFilePersister); ok { 98 err = mover.TryMoveCmpChunkTableWriter(ctx, filename, gcc.writer) 99 if err == nil { 100 return []tableSpec{ 101 { 102 name: addr, 103 chunkCount: uint32(gcc.writer.ChunkCount()), 104 }, 105 }, nil 106 } 107 } 108 109 // Otherwise, write the file through CopyTableFile. 110 r, err := gcc.writer.Reader() 111 if err != nil { 112 return nil, err 113 } 114 defer r.Close() 115 sz := gcc.writer.ContentLength() 116 117 err = tfp.CopyTableFile(ctx, r, filename, sz, uint32(gcc.writer.ChunkCount())) 118 if err != nil { 119 return nil, err 120 } 121 122 return []tableSpec{ 123 { 124 name: addr, 125 chunkCount: uint32(gcc.writer.ChunkCount()), 126 }, 127 }, nil 128 }