github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/binarystorage/layered.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package binarystorage 5 6 import ( 7 "io" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils/set" 11 ) 12 13 type layeredStorage []Storage 14 15 // NewLayeredStorage wraps multiple Storages such all of their metadata 16 // can be listed and fetched. The later entries in the list have lower 17 // precedence than the earlier ones. The first entry in the list is always 18 // used for mutating operations. 19 func NewLayeredStorage(s ...Storage) (Storage, error) { 20 if len(s) <= 1 { 21 return nil, errors.Errorf("expected multiple stores") 22 } 23 return layeredStorage(s), nil 24 } 25 26 // Add implements Storage.Add. 27 // 28 // This method operates on the first Storage passed to NewLayeredStorage. 29 func (s layeredStorage) Add(r io.Reader, m Metadata) error { 30 return s[0].Add(r, m) 31 } 32 33 // Open implements Storage.Open. 34 // 35 // This method calls Open for each Storage passed to NewLayeredStorage in 36 // the order given, and returns the first result where the error does not 37 // satisfy errors.IsNotFound. 38 func (s layeredStorage) Open(v string) (Metadata, io.ReadCloser, error) { 39 var m Metadata 40 var rc io.ReadCloser 41 var err error 42 for _, s := range s { 43 m, rc, err = s.Open(v) 44 if !errors.IsNotFound(err) { 45 break 46 } 47 } 48 return m, rc, err 49 } 50 51 // Metadata implements Storage.Metadata. 52 // 53 // This method calls Metadata for each Storage passed to NewLayeredStorage in 54 // the order given, and returns the first result where the error does not 55 // satisfy errors.IsNotFound. 56 func (s layeredStorage) Metadata(v string) (Metadata, error) { 57 var m Metadata 58 var err error 59 for _, s := range s { 60 m, err = s.Metadata(v) 61 if !errors.IsNotFound(err) { 62 break 63 } 64 } 65 return m, err 66 } 67 68 // AllMetadata implements Storage.AllMetadata. 69 // 70 // This method calls AllMetadata for each Storage passed to NewLayeredStorage 71 // in the order given, and accumulates the results. Any results from a Storage 72 // earlier in the list will take precedence over any others with the same 73 // version. 74 func (s layeredStorage) AllMetadata() ([]Metadata, error) { 75 seen := set.NewStrings() 76 var all []Metadata 77 for _, s := range s { 78 sm, err := s.AllMetadata() 79 if err != nil { 80 return nil, err 81 } 82 for _, m := range sm { 83 if seen.Contains(m.Version) { 84 continue 85 } 86 all = append(all, m) 87 seen.Add(m.Version) 88 } 89 } 90 return all, nil 91 }