github.com/afein/docker@v1.8.2/daemon/graphdriver/fsdiff.go (about) 1 // +build daemon 2 3 package graphdriver 4 5 import ( 6 "time" 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/ioutils" 12 ) 13 14 // naiveDiffDriver takes a ProtoDriver and adds the 15 // capability of the Diffing methods which it may or may not 16 // support on its own. See the comment on the exported 17 // NaiveDiffDriver function below. 18 // Notably, the AUFS driver doesn't need to be wrapped like this. 19 type naiveDiffDriver struct { 20 ProtoDriver 21 } 22 23 // NaiveDiffDriver returns a fully functional driver that wraps the 24 // given ProtoDriver and adds the capability of the following methods which 25 // it may or may not support on its own: 26 // Diff(id, parent string) (archive.Archive, error) 27 // Changes(id, parent string) ([]archive.Change, error) 28 // ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) 29 // DiffSize(id, parent string) (size int64, err error) 30 func NaiveDiffDriver(driver ProtoDriver) Driver { 31 return &naiveDiffDriver{ProtoDriver: driver} 32 } 33 34 // Diff produces an archive of the changes between the specified 35 // layer and its parent layer which may be "". 36 func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { 37 driver := gdw.ProtoDriver 38 39 layerFs, err := driver.Get(id, "") 40 if err != nil { 41 return nil, err 42 } 43 44 defer func() { 45 if err != nil { 46 driver.Put(id) 47 } 48 }() 49 50 if parent == "" { 51 archive, err := archive.Tar(layerFs, archive.Uncompressed) 52 if err != nil { 53 return nil, err 54 } 55 return ioutils.NewReadCloserWrapper(archive, func() error { 56 err := archive.Close() 57 driver.Put(id) 58 return err 59 }), nil 60 } 61 62 parentFs, err := driver.Get(parent, "") 63 if err != nil { 64 return nil, err 65 } 66 defer driver.Put(parent) 67 68 changes, err := archive.ChangesDirs(layerFs, parentFs) 69 if err != nil { 70 return nil, err 71 } 72 73 archive, err := archive.ExportChanges(layerFs, changes) 74 if err != nil { 75 return nil, err 76 } 77 78 return ioutils.NewReadCloserWrapper(archive, func() error { 79 err := archive.Close() 80 driver.Put(id) 81 return err 82 }), nil 83 } 84 85 // Changes produces a list of changes between the specified layer 86 // and its parent layer. If parent is "", then all changes will be ADD changes. 87 func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { 88 driver := gdw.ProtoDriver 89 90 layerFs, err := driver.Get(id, "") 91 if err != nil { 92 return nil, err 93 } 94 defer driver.Put(id) 95 96 parentFs := "" 97 98 if parent != "" { 99 parentFs, err = driver.Get(parent, "") 100 if err != nil { 101 return nil, err 102 } 103 defer driver.Put(parent) 104 } 105 106 return archive.ChangesDirs(layerFs, parentFs) 107 } 108 109 // ApplyDiff extracts the changeset from the given diff into the 110 // layer with the specified id and parent, returning the size of the 111 // new layer in bytes. 112 func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) { 113 driver := gdw.ProtoDriver 114 115 // Mount the root filesystem so we can apply the diff/layer. 116 layerFs, err := driver.Get(id, "") 117 if err != nil { 118 return 119 } 120 defer driver.Put(id) 121 122 start := time.Now().UTC() 123 logrus.Debugf("Start untar layer") 124 if size, err = chrootarchive.ApplyUncompressedLayer(layerFs, diff); err != nil { 125 return 126 } 127 logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 128 129 return 130 } 131 132 // DiffSize calculates the changes between the specified layer 133 // and its parent and returns the size in bytes of the changes 134 // relative to its base filesystem directory. 135 func (gdw *naiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { 136 driver := gdw.ProtoDriver 137 138 changes, err := gdw.Changes(id, parent) 139 if err != nil { 140 return 141 } 142 143 layerFs, err := driver.Get(id, "") 144 if err != nil { 145 return 146 } 147 defer driver.Put(id) 148 149 return archive.ChangesSize(layerFs, changes), nil 150 }