| ... | ... |
@@ -129,6 +129,9 @@ func (graph *Graph) Register(layerData Archive, img *Image) error {
|
| 129 | 129 |
|
| 130 | 130 |
// Mktemp creates a temporary sub-directory inside the graph's filesystem. |
| 131 | 131 |
func (graph *Graph) Mktemp(id string) (string, error) {
|
| 132 |
+ if id == "" {
|
|
| 133 |
+ id = GenerateId() |
|
| 134 |
+ } |
|
| 132 | 135 |
tmp, err := NewGraph(path.Join(graph.Root, ":tmp:")) |
| 133 | 136 |
if err != nil {
|
| 134 | 137 |
return "", fmt.Errorf("Couldn't create temp: %s", err)
|
| ... | ... |
@@ -139,13 +142,6 @@ func (graph *Graph) Mktemp(id string) (string, error) {
|
| 139 | 139 |
return tmp.imageRoot(id), nil |
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 |
-// Garbage returns the "garbage", a staging area for deleted images. |
|
| 143 |
-// This allows images to be deleted atomically by os.Rename(), instead of |
|
| 144 |
-// os.RemoveAll() which is prone to race conditions. |
|
| 145 |
-func (graph *Graph) Garbage() (*Graph, error) {
|
|
| 146 |
- return NewGraph(path.Join(graph.Root, ":garbage:")) |
|
| 147 |
-} |
|
| 148 |
- |
|
| 149 | 142 |
// Check if given error is "not empty". |
| 150 | 143 |
// Note: this is the way golang does it internally with os.IsNotExists. |
| 151 | 144 |
func isNotEmpty(err error) bool {
|
| ... | ... |
@@ -166,54 +162,16 @@ func (graph *Graph) Delete(name string) error {
|
| 166 | 166 |
if err != nil {
|
| 167 | 167 |
return err |
| 168 | 168 |
} |
| 169 |
- garbage, err := graph.Garbage() |
|
| 169 |
+ tmp, err := graph.Mktemp("")
|
|
| 170 | 170 |
if err != nil {
|
| 171 | 171 |
return err |
| 172 | 172 |
} |
| 173 | 173 |
graph.idIndex.Delete(id) |
| 174 |
- err = os.Rename(graph.imageRoot(id), garbage.imageRoot(id)) |
|
| 175 |
- if err != nil {
|
|
| 176 |
- // FIXME: this introduces a race condition in Delete() if the image is already present |
|
| 177 |
- // in garbage. Let's store at random names in grabage instead. |
|
| 178 |
- if isNotEmpty(err) {
|
|
| 179 |
- Debugf("The image %s is already present in garbage. Removing it.", id)
|
|
| 180 |
- if err = os.RemoveAll(garbage.imageRoot(id)); err != nil {
|
|
| 181 |
- Debugf("Error while removing the image %s from garbage: %s\n", id, err)
|
|
| 182 |
- return err |
|
| 183 |
- } |
|
| 184 |
- Debugf("Image %s removed from garbage", id)
|
|
| 185 |
- if err = os.Rename(graph.imageRoot(id), garbage.imageRoot(id)); err != nil {
|
|
| 186 |
- return err |
|
| 187 |
- } |
|
| 188 |
- Debugf("Image %s put in the garbage", id)
|
|
| 189 |
- } else {
|
|
| 190 |
- Debugf("Error putting the image %s to garbage: %s\n", id, err)
|
|
| 191 |
- } |
|
| 192 |
- return err |
|
| 193 |
- } |
|
| 194 |
- return nil |
|
| 195 |
-} |
|
| 196 |
- |
|
| 197 |
-// Undelete moves an image back from the garbage to the main graph. |
|
| 198 |
-func (graph *Graph) Undelete(id string) error {
|
|
| 199 |
- garbage, err := graph.Garbage() |
|
| 200 |
- if err != nil {
|
|
| 201 |
- return err |
|
| 202 |
- } |
|
| 203 |
- if err := os.Rename(garbage.imageRoot(id), graph.imageRoot(id)); err != nil {
|
|
| 204 |
- return err |
|
| 205 |
- } |
|
| 206 |
- graph.idIndex.Add(id) |
|
| 207 |
- return nil |
|
| 208 |
-} |
|
| 209 |
- |
|
| 210 |
-// GarbageCollect definitely deletes all images moved to the garbage. |
|
| 211 |
-func (graph *Graph) GarbageCollect() error {
|
|
| 212 |
- garbage, err := graph.Garbage() |
|
| 174 |
+ err = os.Rename(graph.imageRoot(id), tmp) |
|
| 213 | 175 |
if err != nil {
|
| 214 | 176 |
return err |
| 215 | 177 |
} |
| 216 |
- return os.RemoveAll(garbage.Root) |
|
| 178 |
+ return os.RemoveAll(tmp) |
|
| 217 | 179 |
} |
| 218 | 180 |
|
| 219 | 181 |
// Map returns a list of all images in the graph, addressable by ID. |