github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/daemon/graphdriver/fsdiff.go (about) 1 package graphdriver 2 3 import ( 4 "io" 5 "time" 6 "fmt" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/pkg/archive" 10 "github.com/docker/docker/pkg/chrootarchive" 11 "github.com/docker/docker/pkg/idtools" 12 "github.com/docker/docker/pkg/ioutils" 13 ) 14 15 var ( 16 // ApplyUncompressedLayer defines the unpack method used by the graph 17 // driver. 18 ApplyUncompressedLayer = chrootarchive.ApplyUncompressedLayer 19 ) 20 21 // NaiveDiffDriver takes a ProtoDriver and adds the 22 // capability of the Diffing methods which it may or may not 23 // support on its own. See the comment on the exported 24 // NewNaiveDiffDriver function below. 25 // Notably, the AUFS driver doesn't need to be wrapped like this. 26 type NaiveDiffDriver struct { 27 ProtoDriver 28 uidMaps []idtools.IDMap 29 gidMaps []idtools.IDMap 30 } 31 32 // NewNaiveDiffDriver returns a fully functional driver that wraps the 33 // given ProtoDriver and adds the capability of the following methods which 34 // it may or may not support on its own: 35 // Diff(id, parent string) (archive.Archive, error) 36 // Changes(id, parent string) ([]archive.Change, error) 37 // ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) 38 // DiffSize(id, parent string) (size int64, err error) 39 func NewNaiveDiffDriver(driver ProtoDriver, uidMaps, gidMaps []idtools.IDMap) Driver { 40 return &NaiveDiffDriver{ProtoDriver: driver, 41 uidMaps: uidMaps, 42 gidMaps: gidMaps} 43 } 44 45 // Diff produces an archive of the changes between the specified 46 // layer and its parent layer which may be "". 47 func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err error) { 48 startTime := time.Now() 49 driver := gdw.ProtoDriver 50 51 layerFs, err := driver.Get(id, "") 52 if err != nil { 53 return nil, err 54 } 55 56 defer func() { 57 if err != nil { 58 driver.Put(id) 59 } 60 }() 61 62 if parent == "" { 63 archive, err := archive.Tar(layerFs, archive.Uncompressed) 64 if err != nil { 65 return nil, err 66 } 67 return ioutils.NewReadCloserWrapper(archive, func() error { 68 err := archive.Close() 69 driver.Put(id) 70 return err 71 }), nil 72 } 73 74 parentFs, err := driver.Get(parent, "") 75 if err != nil { 76 return nil, err 77 } 78 defer driver.Put(parent) 79 80 changes, err := archive.ChangesDirs(layerFs, parentFs) 81 if err != nil { 82 return nil, err 83 } 84 85 archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps) 86 if err != nil { 87 return nil, err 88 } 89 90 return ioutils.NewReadCloserWrapper(archive, func() error { 91 err := archive.Close() 92 driver.Put(id) 93 94 // NaiveDiffDriver compares file metadata with parent layers. Parent layers 95 // are extracted from tar's with full second precision on modified time. 96 // We need this hack here to make sure calls within same second receive 97 // correct result. 98 time.Sleep(startTime.Truncate(time.Second).Add(time.Second).Sub(time.Now())) 99 return err 100 }), nil 101 } 102 103 // Changes produces a list of changes between the specified layer 104 // and its parent layer. If parent is "", then all changes will be ADD changes. 105 func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { 106 driver := gdw.ProtoDriver 107 108 layerFs, err := driver.Get(id, "") 109 if err != nil { 110 return nil, err 111 } 112 defer driver.Put(id) 113 114 parentFs := "" 115 116 if parent != "" { 117 parentFs, err = driver.Get(parent, "") 118 if err != nil { 119 return nil, err 120 } 121 defer driver.Put(parent) 122 } 123 124 return archive.ChangesDirs(layerFs, parentFs) 125 } 126 127 // ApplyDiff extracts the changeset from the given diff into the 128 // layer with the specified id and parent, returning the size of the 129 // new layer in bytes. 130 func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff io.Reader) (size int64, err error) { 131 fmt.Println("daemon/graphdriver/fsdiff.go ApplyDiff()") 132 driver := gdw.ProtoDriver 133 134 // Mount the root filesystem so we can apply the diff/layer. 135 layerFs, err := driver.Get(id, "") 136 if err != nil { 137 return 138 } 139 defer driver.Put(id) 140 141 fmt.Println("daemon/graphdriver/fsdiff.go ApplyDiff() driverget") 142 options := &archive.TarOptions{UIDMaps: gdw.uidMaps, 143 GIDMaps: gdw.gidMaps} 144 start := time.Now().UTC() 145 logrus.Debug("Start untar layer") 146 fmt.Println("daemon/graphdriver/fsdiff.go ApplyDiff() before applyuncompressedlayer()") 147 if size, err = ApplyUncompressedLayer(layerFs, diff, options); err != nil { 148 return 149 } 150 logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 151 fmt.Println("daemon/graphdriver/fsdiff.go ApplyDiff() after applyuncompressedlayer()") 152 153 return 154 } 155 156 // DiffSize calculates the changes between the specified layer 157 // and its parent and returns the size in bytes of the changes 158 // relative to its base filesystem directory. 159 func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { 160 driver := gdw.ProtoDriver 161 162 changes, err := gdw.Changes(id, parent) 163 if err != nil { 164 return 165 } 166 167 layerFs, err := driver.Get(id, "") 168 if err != nil { 169 return 170 } 171 defer driver.Put(id) 172 173 return archive.ChangesSize(layerFs, changes), nil 174 }