go.temporal.io/server@v1.23.0/common/archiver/provider/provider.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  //go:generate mockgen -copyright_file ../../../LICENSE -package $GOPACKAGE -source $GOFILE -destination provider_mock.go
    26  
    27  package provider
    28  
    29  import (
    30  	"errors"
    31  	"sync"
    32  
    33  	"go.temporal.io/server/common/archiver/gcloud"
    34  
    35  	"go.temporal.io/server/common/archiver"
    36  	"go.temporal.io/server/common/archiver/filestore"
    37  	"go.temporal.io/server/common/archiver/s3store"
    38  	"go.temporal.io/server/common/config"
    39  )
    40  
    41  var (
    42  	// ErrUnknownScheme is the error for unknown archiver scheme
    43  	ErrUnknownScheme = errors.New("unknown archiver scheme")
    44  	// ErrNotSupported is the error for not supported archiver implementation
    45  	ErrNotSupported = errors.New("archiver provider not supported")
    46  	// ErrBootstrapContainerNotFound is the error for unable to find the bootstrap container given serviceName
    47  	ErrBootstrapContainerNotFound = errors.New("unable to find bootstrap container for the given service name")
    48  	// ErrArchiverConfigNotFound is the error for unable to find the config for an archiver given scheme
    49  	ErrArchiverConfigNotFound = errors.New("unable to find archiver config for the given scheme")
    50  	// ErrBootstrapContainerAlreadyRegistered is the error for registering multiple containers for the same serviceName
    51  	ErrBootstrapContainerAlreadyRegistered = errors.New("bootstrap container has already been registered")
    52  )
    53  
    54  type (
    55  	// ArchiverProvider returns history or visibility archiver based on the scheme and serviceName.
    56  	// The archiver for each combination of scheme and serviceName will be created only once and cached.
    57  	ArchiverProvider interface {
    58  		RegisterBootstrapContainer(
    59  			serviceName string,
    60  			historyContainer *archiver.HistoryBootstrapContainer,
    61  			visibilityContainter *archiver.VisibilityBootstrapContainer,
    62  		) error
    63  		GetHistoryArchiver(scheme, serviceName string) (archiver.HistoryArchiver, error)
    64  		GetVisibilityArchiver(scheme, serviceName string) (archiver.VisibilityArchiver, error)
    65  	}
    66  
    67  	archiverProvider struct {
    68  		sync.RWMutex
    69  
    70  		historyArchiverConfigs    *config.HistoryArchiverProvider
    71  		visibilityArchiverConfigs *config.VisibilityArchiverProvider
    72  
    73  		// Key for the container is just serviceName
    74  		historyContainers    map[string]*archiver.HistoryBootstrapContainer
    75  		visibilityContainers map[string]*archiver.VisibilityBootstrapContainer
    76  
    77  		// Key for the archiver is scheme + serviceName
    78  		historyArchivers    map[string]archiver.HistoryArchiver
    79  		visibilityArchivers map[string]archiver.VisibilityArchiver
    80  	}
    81  )
    82  
    83  // NewArchiverProvider returns a new Archiver provider
    84  func NewArchiverProvider(
    85  	historyArchiverConfigs *config.HistoryArchiverProvider,
    86  	visibilityArchiverConfigs *config.VisibilityArchiverProvider,
    87  ) ArchiverProvider {
    88  	return &archiverProvider{
    89  		historyArchiverConfigs:    historyArchiverConfigs,
    90  		visibilityArchiverConfigs: visibilityArchiverConfigs,
    91  		historyContainers:         make(map[string]*archiver.HistoryBootstrapContainer),
    92  		visibilityContainers:      make(map[string]*archiver.VisibilityBootstrapContainer),
    93  		historyArchivers:          make(map[string]archiver.HistoryArchiver),
    94  		visibilityArchivers:       make(map[string]archiver.VisibilityArchiver),
    95  	}
    96  }
    97  
    98  // RegisterBootstrapContainer stores the given bootstrap container given the serviceName
    99  // The container should be registered when a service starts up and before GetArchiver() is ever called.
   100  // Later calls to GetArchiver() will used the registered container to initialize new archivers.
   101  // If the container for a service has already registered, and this method is invoked for that service again
   102  // with an non-nil container, an error will be returned.
   103  func (p *archiverProvider) RegisterBootstrapContainer(
   104  	serviceName string,
   105  	historyContainer *archiver.HistoryBootstrapContainer,
   106  	visibilityContainter *archiver.VisibilityBootstrapContainer,
   107  ) error {
   108  	p.Lock()
   109  	defer p.Unlock()
   110  
   111  	if _, ok := p.historyContainers[serviceName]; ok && historyContainer != nil {
   112  		return ErrBootstrapContainerAlreadyRegistered
   113  	}
   114  	if _, ok := p.visibilityContainers[serviceName]; ok && visibilityContainter != nil {
   115  		return ErrBootstrapContainerAlreadyRegistered
   116  	}
   117  
   118  	if historyContainer != nil {
   119  		p.historyContainers[serviceName] = historyContainer
   120  	}
   121  	if visibilityContainter != nil {
   122  		p.visibilityContainers[serviceName] = visibilityContainter
   123  	}
   124  	return nil
   125  }
   126  
   127  func (p *archiverProvider) GetHistoryArchiver(scheme, serviceName string) (historyArchiver archiver.HistoryArchiver, err error) {
   128  	archiverKey := p.getArchiverKey(scheme, serviceName)
   129  	p.RLock()
   130  	if historyArchiver, ok := p.historyArchivers[archiverKey]; ok {
   131  		p.RUnlock()
   132  		return historyArchiver, nil
   133  	}
   134  	p.RUnlock()
   135  
   136  	container, ok := p.historyContainers[serviceName]
   137  	if !ok {
   138  		return nil, ErrBootstrapContainerNotFound
   139  	}
   140  
   141  	switch scheme {
   142  	case filestore.URIScheme:
   143  		if p.historyArchiverConfigs.Filestore == nil {
   144  			return nil, ErrArchiverConfigNotFound
   145  		}
   146  		historyArchiver, err = filestore.NewHistoryArchiver(container, p.historyArchiverConfigs.Filestore)
   147  
   148  	case gcloud.URIScheme:
   149  		if p.historyArchiverConfigs.Gstorage == nil {
   150  			return nil, ErrArchiverConfigNotFound
   151  		}
   152  
   153  		historyArchiver, err = gcloud.NewHistoryArchiver(container, p.historyArchiverConfigs.Gstorage)
   154  
   155  	case s3store.URIScheme:
   156  		if p.historyArchiverConfigs.S3store == nil {
   157  			return nil, ErrArchiverConfigNotFound
   158  		}
   159  		historyArchiver, err = s3store.NewHistoryArchiver(container, p.historyArchiverConfigs.S3store)
   160  	default:
   161  		return nil, ErrUnknownScheme
   162  	}
   163  
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	p.Lock()
   169  	defer p.Unlock()
   170  	if existingHistoryArchiver, ok := p.historyArchivers[archiverKey]; ok {
   171  		return existingHistoryArchiver, nil
   172  	}
   173  	p.historyArchivers[archiverKey] = historyArchiver
   174  	return historyArchiver, nil
   175  }
   176  
   177  func (p *archiverProvider) GetVisibilityArchiver(scheme, serviceName string) (archiver.VisibilityArchiver, error) {
   178  	archiverKey := p.getArchiverKey(scheme, serviceName)
   179  	p.RLock()
   180  	if visibilityArchiver, ok := p.visibilityArchivers[archiverKey]; ok {
   181  		p.RUnlock()
   182  		return visibilityArchiver, nil
   183  	}
   184  	p.RUnlock()
   185  
   186  	container, ok := p.visibilityContainers[serviceName]
   187  	if !ok {
   188  		return nil, ErrBootstrapContainerNotFound
   189  	}
   190  
   191  	var visibilityArchiver archiver.VisibilityArchiver
   192  	var err error
   193  
   194  	switch scheme {
   195  	case filestore.URIScheme:
   196  		if p.visibilityArchiverConfigs.Filestore == nil {
   197  			return nil, ErrArchiverConfigNotFound
   198  		}
   199  		visibilityArchiver, err = filestore.NewVisibilityArchiver(container, p.visibilityArchiverConfigs.Filestore)
   200  	case s3store.URIScheme:
   201  		if p.visibilityArchiverConfigs.S3store == nil {
   202  			return nil, ErrArchiverConfigNotFound
   203  		}
   204  		visibilityArchiver, err = s3store.NewVisibilityArchiver(container, p.visibilityArchiverConfigs.S3store)
   205  	case gcloud.URIScheme:
   206  		if p.visibilityArchiverConfigs.Gstorage == nil {
   207  			return nil, ErrArchiverConfigNotFound
   208  		}
   209  		visibilityArchiver, err = gcloud.NewVisibilityArchiver(container, p.visibilityArchiverConfigs.Gstorage)
   210  
   211  	default:
   212  		return nil, ErrUnknownScheme
   213  	}
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	p.Lock()
   219  	defer p.Unlock()
   220  	if existingVisibilityArchiver, ok := p.visibilityArchivers[archiverKey]; ok {
   221  		return existingVisibilityArchiver, nil
   222  	}
   223  	p.visibilityArchivers[archiverKey] = visibilityArchiver
   224  	return visibilityArchiver, nil
   225  
   226  }
   227  
   228  func (p *archiverProvider) getArchiverKey(scheme, serviceName string) string {
   229  	return scheme + ":" + serviceName
   230  }