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  }