github.com/uber/kraken@v0.1.4/lib/store/ca_download_store.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package store 15 16 import ( 17 "fmt" 18 "os" 19 20 "github.com/uber/kraken/lib/store/base" 21 "github.com/uber/kraken/lib/store/metadata" 22 "github.com/andres-erbsen/clock" 23 "github.com/uber-go/tally" 24 ) 25 26 // CADownloadStore allows simultaneously downloading and uploading 27 // content-adddressable files. 28 type CADownloadStore struct { 29 backend base.FileStore 30 downloadState base.FileState 31 cacheState base.FileState 32 cleanup *cleanupManager 33 } 34 35 // NewCADownloadStore creates a new CADownloadStore. 36 func NewCADownloadStore(config CADownloadStoreConfig, stats tally.Scope) (*CADownloadStore, error) { 37 stats = stats.Tagged(map[string]string{ 38 "module": "cadownloadstore", 39 }) 40 41 for _, dir := range []string{config.DownloadDir, config.CacheDir} { 42 if err := os.MkdirAll(dir, 0775); err != nil { 43 return nil, fmt.Errorf("mkdir %s: %s", dir, err) 44 } 45 } 46 47 backend := base.NewCASFileStore(clock.New()) 48 downloadState := base.NewFileState(config.DownloadDir) 49 cacheState := base.NewFileState(config.CacheDir) 50 51 cleanup, err := newCleanupManager(clock.New(), stats) 52 if err != nil { 53 return nil, fmt.Errorf("new cleanup manager: %s", err) 54 } 55 cleanup.addJob( 56 "download", 57 config.DownloadCleanup, 58 backend.NewFileOp().AcceptState(downloadState)) 59 cleanup.addJob( 60 "cache", 61 config.CacheCleanup, 62 backend.NewFileOp().AcceptState(cacheState)) 63 64 return &CADownloadStore{ 65 backend: backend, 66 downloadState: downloadState, 67 cacheState: cacheState, 68 cleanup: cleanup, 69 }, nil 70 } 71 72 // Close terminates all goroutines started by s. 73 func (s *CADownloadStore) Close() { 74 s.cleanup.stop() 75 } 76 77 // CreateDownloadFile creates an empty download file initialized with length. 78 func (s *CADownloadStore) CreateDownloadFile(name string, length int64) error { 79 return s.backend.NewFileOp().CreateFile(name, s.downloadState, length) 80 } 81 82 // GetDownloadFileReadWriter returns a FileReadWriter for name. 83 func (s *CADownloadStore) GetDownloadFileReadWriter(name string) (FileReadWriter, error) { 84 return s.backend.NewFileOp().AcceptState(s.downloadState).GetFileReadWriter(name) 85 } 86 87 // MoveDownloadFileToCache moves a download file to the cache. 88 func (s *CADownloadStore) MoveDownloadFileToCache(name string) error { 89 return s.backend.NewFileOp().AcceptState(s.downloadState).MoveFile(name, s.cacheState) 90 } 91 92 // GetCacheFileReader gets a cache file reader. Implemented for compatibility with 93 // other stores. 94 func (s *CADownloadStore) GetCacheFileReader(name string) (FileReader, error) { 95 return s.Cache().GetFileReader(name) 96 } 97 98 // GetCacheFileStat stats a cache file. Implemented for compatibility with other 99 // stores. 100 func (s *CADownloadStore) GetCacheFileStat(name string) (os.FileInfo, error) { 101 return s.Cache().GetFileStat(name) 102 } 103 104 // InCacheError returns true for errors originating from file store operations 105 // which do not accept files in cache state. 106 func (s *CADownloadStore) InCacheError(err error) bool { 107 fse, ok := err.(*base.FileStateError) 108 return ok && fse.State == s.cacheState 109 } 110 111 // InDownloadError returns true for errors originating from file store operations 112 // which do not accept files in download state. 113 func (s *CADownloadStore) InDownloadError(err error) bool { 114 fse, ok := err.(*base.FileStateError) 115 return ok && fse.State == s.downloadState 116 } 117 118 // CADownloadStoreScope scopes what states an operation may be accepted within. 119 // Should only be used for read / write operations which are acceptable in any 120 // state. 121 type CADownloadStoreScope struct { 122 store *CADownloadStore 123 op base.FileOp 124 } 125 126 func (s *CADownloadStore) states() *CADownloadStoreScope { 127 return &CADownloadStoreScope{ 128 store: s, 129 op: s.backend.NewFileOp(), 130 } 131 } 132 133 func (a *CADownloadStoreScope) download() *CADownloadStoreScope { 134 a.op = a.op.AcceptState(a.store.downloadState) 135 return a 136 } 137 138 func (a *CADownloadStoreScope) cache() *CADownloadStoreScope { 139 a.op = a.op.AcceptState(a.store.cacheState) 140 return a 141 } 142 143 // Download scopes the store to files in the download state. 144 func (s *CADownloadStore) Download() *CADownloadStoreScope { 145 return s.states().download() 146 } 147 148 // Cache scopes the store to files in the cache state. 149 func (s *CADownloadStore) Cache() *CADownloadStoreScope { 150 return s.states().cache() 151 } 152 153 // Any scopes the store to files in any state. 154 func (s *CADownloadStore) Any() *CADownloadStoreScope { 155 return s.states().download().cache() 156 } 157 158 // GetFileReader returns a reader for name. 159 func (a *CADownloadStoreScope) GetFileReader(name string) (FileReader, error) { 160 return a.op.GetFileReader(name) 161 } 162 163 // GetFileStat returns file info for name. 164 func (a *CADownloadStoreScope) GetFileStat(name string) (os.FileInfo, error) { 165 return a.op.GetFileStat(name) 166 } 167 168 // DeleteFile deletes name. 169 func (a *CADownloadStoreScope) DeleteFile(name string) error { 170 return a.op.DeleteFile(name) 171 } 172 173 // GetMetadata returns the metadata content of md for name. 174 func (a *CADownloadStoreScope) GetMetadata(name string, md metadata.Metadata) error { 175 return a.op.GetFileMetadata(name, md) 176 } 177 178 // SetMetadata writes b to metadata content of md for name. 179 func (a *CADownloadStoreScope) SetMetadata( 180 name string, md metadata.Metadata) (updated bool, err error) { 181 182 return a.op.SetFileMetadata(name, md) 183 } 184 185 // SetMetadataAt writes b to metadata content of md starting at index i for name. 186 func (a *CADownloadStoreScope) SetMetadataAt( 187 name string, md metadata.Metadata, b []byte, offset int64) (updated bool, err error) { 188 189 return a.op.SetFileMetadataAt(name, md, b, offset) 190 } 191 192 // GetOrSetMetadata returns the metadata content of md for name, or 193 // initializes the metadata content to b if not set. 194 func (a *CADownloadStoreScope) GetOrSetMetadata(name string, md metadata.Metadata) error { 195 return a.op.GetOrSetFileMetadata(name, md) 196 }