Browse code

added ability to iterate over all indexes and use index.Iterate() instead of ReadDir() to walk over the graph

Signed-off-by: Roman Strashkin <roman.strashkin@gmail.com>

Roman Strashkin authored on 2015/06/20 00:01:39
Showing 9 changed files
... ...
@@ -884,10 +884,7 @@ func (daemon *Daemon) ContainerGraph() *graphdb.Database {
884 884
 
885 885
 func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*graph.Image, error) {
886 886
 	// Retrieve all images
887
-	images, err := daemon.Graph().Map()
888
-	if err != nil {
889
-		return nil, err
890
-	}
887
+	images := daemon.Graph().Map()
891 888
 
892 889
 	// Store the tree in a map of map (map[parentId][childId])
893 890
 	imageMap := make(map[string]map[string]struct{})
... ...
@@ -55,10 +55,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
55 55
 		tag = ""
56 56
 	}
57 57
 
58
-	byParents, err := daemon.Graph().ByParent()
59
-	if err != nil {
60
-		return err
61
-	}
58
+	byParents := daemon.Graph().ByParent()
62 59
 
63 60
 	repos := daemon.Repositories().ByID()[img.ID]
64 61
 
... ...
@@ -17,7 +17,7 @@ import (
17 17
 )
18 18
 
19 19
 func (daemon *Daemon) SystemInfo() (*types.Info, error) {
20
-	images, _ := daemon.Graph().Map()
20
+	images := daemon.Graph().Map()
21 21
 	var imgcount int
22 22
 	if images == nil {
23 23
 		imgcount = 0
... ...
@@ -327,42 +327,33 @@ func (graph *Graph) Delete(name string) error {
327 327
 }
328 328
 
329 329
 // Map returns a list of all images in the graph, addressable by ID.
330
-func (graph *Graph) Map() (map[string]*Image, error) {
330
+func (graph *Graph) Map() map[string]*Image {
331 331
 	images := make(map[string]*Image)
332
-	err := graph.walkAll(func(image *Image) {
332
+	graph.walkAll(func(image *Image) {
333 333
 		images[image.ID] = image
334 334
 	})
335
-	if err != nil {
336
-		return nil, err
337
-	}
338
-	return images, nil
335
+	return images
339 336
 }
340 337
 
341 338
 // walkAll iterates over each image in the graph, and passes it to a handler.
342 339
 // The walking order is undetermined.
343
-func (graph *Graph) walkAll(handler func(*Image)) error {
344
-	files, err := ioutil.ReadDir(graph.root)
345
-	if err != nil {
346
-		return err
347
-	}
348
-	for _, st := range files {
349
-		if img, err := graph.Get(st.Name()); err != nil {
350
-			// Skip image
351
-			continue
340
+func (graph *Graph) walkAll(handler func(*Image)) {
341
+	graph.idIndex.Iterate(func(id string) {
342
+		if img, err := graph.Get(id); err != nil {
343
+			return
352 344
 		} else if handler != nil {
353 345
 			handler(img)
354 346
 		}
355
-	}
356
-	return nil
347
+	})
357 348
 }
358 349
 
359 350
 // ByParent returns a lookup table of images by their parent.
360 351
 // If an image of id ID has 3 children images, then the value for key ID
361 352
 // will be a list of 3 images.
362 353
 // If an image has no children, it will not have an entry in the table.
363
-func (graph *Graph) ByParent() (map[string][]*Image, error) {
354
+func (graph *Graph) ByParent() map[string][]*Image {
364 355
 	byParent := make(map[string][]*Image)
365
-	err := graph.walkAll(func(img *Image) {
356
+	graph.walkAll(func(img *Image) {
366 357
 		parent, err := graph.Get(img.Parent)
367 358
 		if err != nil {
368 359
 			return
... ...
@@ -373,25 +364,22 @@ func (graph *Graph) ByParent() (map[string][]*Image, error) {
373 373
 			byParent[parent.ID] = []*Image{img}
374 374
 		}
375 375
 	})
376
-	return byParent, err
376
+	return byParent
377 377
 }
378 378
 
379 379
 // Heads returns all heads in the graph, keyed by id.
380 380
 // A head is an image which is not the parent of another image in the graph.
381
-func (graph *Graph) Heads() (map[string]*Image, error) {
381
+func (graph *Graph) Heads() map[string]*Image {
382 382
 	heads := make(map[string]*Image)
383
-	byParent, err := graph.ByParent()
384
-	if err != nil {
385
-		return nil, err
386
-	}
387
-	err = graph.walkAll(func(image *Image) {
383
+	byParent := graph.ByParent()
384
+	graph.walkAll(func(image *Image) {
388 385
 		// If it's not in the byParent lookup table, then
389 386
 		// it's not a parent -> so it's a head!
390 387
 		if _, exists := byParent[image.ID]; !exists {
391 388
 			heads[image.ID] = image
392 389
 		}
393 390
 	})
394
-	return heads, err
391
+	return heads
395 392
 }
396 393
 
397 394
 func (graph *Graph) imageRoot(id string) string {
... ...
@@ -56,9 +56,8 @@ func TestInit(t *testing.T) {
56 56
 		t.Fatal(err)
57 57
 	}
58 58
 	// Map() should be empty
59
-	if l, err := graph.Map(); err != nil {
60
-		t.Fatal(err)
61
-	} else if len(l) != 0 {
59
+	l := graph.Map()
60
+	if len(l) != 0 {
62 61
 		t.Fatalf("len(Map()) should return %d, not %d", 0, len(l))
63 62
 	}
64 63
 }
... ...
@@ -110,10 +109,8 @@ func TestGraphCreate(t *testing.T) {
110 110
 	if img.DockerVersion != dockerversion.VERSION {
111 111
 		t.Fatalf("Wrong docker_version: should be '%s', not '%s'", dockerversion.VERSION, img.DockerVersion)
112 112
 	}
113
-	images, err := graph.Map()
114
-	if err != nil {
115
-		t.Fatal(err)
116
-	} else if l := len(images); l != 1 {
113
+	images := graph.Map()
114
+	if l := len(images); l != 1 {
117 115
 		t.Fatalf("Wrong number of images. Should be %d, not %d", 1, l)
118 116
 	}
119 117
 	if images[img.ID] == nil {
... ...
@@ -137,9 +134,8 @@ func TestRegister(t *testing.T) {
137 137
 	if err != nil {
138 138
 		t.Fatal(err)
139 139
 	}
140
-	if images, err := graph.Map(); err != nil {
141
-		t.Fatal(err)
142
-	} else if l := len(images); l != 1 {
140
+	images := graph.Map()
141
+	if l := len(images); l != 1 {
143 142
 		t.Fatalf("Wrong number of images. Should be %d, not %d", 1, l)
144 143
 	}
145 144
 	if resultImg, err := graph.Get(image.ID); err != nil {
... ...
@@ -254,10 +250,7 @@ func TestByParent(t *testing.T) {
254 254
 	_ = graph.Register(childImage1, archive2)
255 255
 	_ = graph.Register(childImage2, archive3)
256 256
 
257
-	byParent, err := graph.ByParent()
258
-	if err != nil {
259
-		t.Fatal(err)
260
-	}
257
+	byParent := graph.ByParent()
261 258
 	numChildren := len(byParent[parentImage.ID])
262 259
 	if numChildren != 2 {
263 260
 		t.Fatalf("Expected 2 children, found %d", numChildren)
... ...
@@ -277,9 +270,8 @@ func createTestImage(graph *Graph, t *testing.T) *Image {
277 277
 }
278 278
 
279 279
 func assertNImages(graph *Graph, t *testing.T, n int) {
280
-	if images, err := graph.Map(); err != nil {
281
-		t.Fatal(err)
282
-	} else if actualN := len(images); actualN != n {
280
+	images := graph.Map()
281
+	if actualN := len(images); actualN != n {
283 282
 		t.Fatalf("Expected %d images, found %d", n, actualN)
284 283
 	}
285 284
 }
... ...
@@ -58,12 +58,9 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
58 58
 	_, filtLabel = imageFilters["label"]
59 59
 
60 60
 	if config.All && filtTagged {
61
-		allImages, err = s.graph.Map()
61
+		allImages = s.graph.Map()
62 62
 	} else {
63
-		allImages, err = s.graph.Heads()
64
-	}
65
-	if err != nil {
66
-		return nil, err
63
+		allImages = s.graph.Heads()
67 64
 	}
68 65
 
69 66
 	lookup := make(map[string]*types.Image)
... ...
@@ -31,10 +31,7 @@ func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
31 31
 	if err := os.Mkdir(repoDir, os.ModeDir); err != nil {
32 32
 		return err
33 33
 	}
34
-	images, err := s.graph.Map()
35
-	if err != nil {
36
-		return err
37
-	}
34
+	images := s.graph.Map()
38 35
 	excludes := make([]string, len(images))
39 36
 	i := 0
40 37
 	for k := range images {
... ...
@@ -108,3 +108,13 @@ func (idx *TruncIndex) Get(s string) (string, error) {
108 108
 	}
109 109
 	return "", fmt.Errorf("no such id: %s", s)
110 110
 }
111
+
112
+// Iterates over all stored IDs, and passes each of them to the given handler
113
+func (idx *TruncIndex) Iterate(handler func(id string)) {
114
+	idx.RLock()
115
+	defer idx.RUnlock()
116
+	idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error {
117
+		handler(string(prefix))
118
+		return nil
119
+	})
120
+}
... ...
@@ -96,6 +96,29 @@ func TestTruncIndex(t *testing.T) {
96 96
 	assertIndexGet(t, index, id[:7], id, false)
97 97
 	assertIndexGet(t, index, id[:15], id, false)
98 98
 	assertIndexGet(t, index, id, id, false)
99
+
100
+	assertIndexIterate(t)
101
+}
102
+
103
+func assertIndexIterate(t *testing.T) {
104
+	ids := []string{
105
+		"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
106
+		"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
107
+		"37b36c2c326ccc11e726eee6ee78a0baf166ef96",
108
+		"46b36c2c326ccc11e726eee6ee78a0baf166ef96",
109
+	}
110
+
111
+	index := NewTruncIndex(ids)
112
+
113
+	index.Iterate(func(targetId string) {
114
+		for _, id := range ids {
115
+			if targetId == id {
116
+				return
117
+			}
118
+		}
119
+
120
+		t.Fatalf("An unknown ID '%s'", targetId)
121
+	})
99 122
 }
100 123
 
101 124
 func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {