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