github.com/xmidt-org/webpa-common@v1.11.9/service/accessor.go (about)

     1  package service
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/rand"
     7  	"sync"
     8  )
     9  
    10  var (
    11  	errNoInstances     = errors.New("There are no instances available")
    12  	errNoFailOvers     = errors.New("no failover instances available")
    13  	errFailOversFailed = errors.New("failovers could not find an instance")
    14  )
    15  
    16  // Accessor holds a hash of server nodes.
    17  type Accessor interface {
    18  	// Get fetches the server node associated with a particular key.
    19  	Get(key []byte) (string, error)
    20  }
    21  
    22  // AccessorFunc is a function type that implements Accessor
    23  type AccessorFunc func([]byte) (string, error)
    24  
    25  func (af AccessorFunc) Get(key []byte) (string, error) {
    26  	return af(key)
    27  }
    28  
    29  type emptyAccessor struct{}
    30  
    31  func (ea emptyAccessor) Get([]byte) (string, error) {
    32  	return "", errNoInstances
    33  }
    34  
    35  // EmptyAccessor returns an Accessor that always returns an error from Get.
    36  func EmptyAccessor() Accessor {
    37  	return emptyAccessor{}
    38  }
    39  
    40  // MapAccessor is a static Accessor that honors a set of known keys.  Any other key
    41  // will result in an error.  Mostly useful for testing.
    42  type MapAccessor map[string]string
    43  
    44  func (ma MapAccessor) Get(key []byte) (string, error) {
    45  	if v, ok := ma[string(key)]; ok {
    46  		return v, nil
    47  	} else {
    48  		return "", fmt.Errorf("No such key: %s", string(key))
    49  	}
    50  }
    51  
    52  // UpdatableAccessor is an Accessor whose contents can be mutated safely under concurrency.
    53  // The zero value of this struct is a valid Accessor initialized with no instances.  Get will
    54  // return an error until there is an update with at least (1) instance.
    55  type UpdatableAccessor struct {
    56  	lock sync.RWMutex
    57  
    58  	err     error
    59  	current Accessor
    60  }
    61  
    62  // Get hashes the key against the current set of instances to select an instance consistently.
    63  // This method will return an error if this instance isn't updated yet or has been updated with
    64  // no instances.
    65  func (ua *UpdatableAccessor) Get(key []byte) (instance string, err error) {
    66  	ua.lock.RLock()
    67  
    68  	switch {
    69  	case ua.err != nil:
    70  		err = ua.err
    71  
    72  	case ua.current != nil:
    73  		instance, err = ua.current.Get(key)
    74  
    75  	default:
    76  		err = errNoInstances
    77  	}
    78  
    79  	ua.lock.RUnlock()
    80  	return
    81  }
    82  
    83  // SetError clears the instances being used by this instance and sets the error to be returned
    84  // by Get with every call.  This error will be returned by Get until an update with one or more instances
    85  // occurs.
    86  func (ua *UpdatableAccessor) SetError(err error) {
    87  	ua.lock.Lock()
    88  	ua.err = err
    89  	ua.current = nil
    90  	ua.lock.Unlock()
    91  }
    92  
    93  // SetInstances changes the instances used by this UpdateAccessor, clearing any error.  Note that Get will
    94  // still return an error if a is nil or empty.
    95  func (ua *UpdatableAccessor) SetInstances(a Accessor) {
    96  	ua.lock.Lock()
    97  	ua.err = nil
    98  	ua.current = a
    99  	ua.lock.Unlock()
   100  }
   101  
   102  // Update sets both the instances and the Get error in a single, atomic call.
   103  func (ua *UpdatableAccessor) Update(a Accessor, err error) {
   104  	ua.lock.Lock()
   105  	ua.err = err
   106  	ua.current = a
   107  	ua.lock.Unlock()
   108  }
   109  
   110  type RouteTraffic interface {
   111  	Route(instance string) error
   112  }
   113  
   114  type emptyRouter struct {
   115  }
   116  
   117  func (r emptyRouter) Route(instance string) error {
   118  	return nil
   119  }
   120  
   121  func DefaultTrafficRouter() RouteTraffic {
   122  	return emptyRouter{}
   123  }
   124  
   125  type AccessorQueue interface {
   126  	Order([]string) []string
   127  }
   128  
   129  type emptyQueue struct {
   130  	r *rand.Rand
   131  }
   132  
   133  func DefaultOrder() AccessorQueue {
   134  	return emptyQueue{}
   135  }
   136  
   137  func (r emptyQueue) Order(keys []string) []string {
   138  	return keys
   139  }
   140  
   141  type AccessorValue struct {
   142  	Accessor Accessor
   143  	Err      error
   144  }
   145  type LayeredAccessor interface {
   146  	Accessor
   147  
   148  	SetError(err error)
   149  	SetPrimary(a Accessor)
   150  	UpdatePrimary(a Accessor, err error)
   151  	SetFailOver(failover map[string]AccessorValue)
   152  	UpdateFailOver(key string, a Accessor, err error)
   153  }
   154  
   155  type layeredAccessor struct {
   156  	router        RouteTraffic
   157  	accessorQueue AccessorQueue
   158  
   159  	err      error
   160  	primary  Accessor
   161  	failover map[string]AccessorValue
   162  
   163  	lock sync.RWMutex
   164  }
   165  
   166  func NewLayeredAccesor(router RouteTraffic, chooser AccessorQueue) LayeredAccessor {
   167  	return &layeredAccessor{
   168  		router:        router,
   169  		accessorQueue: chooser,
   170  		failover:      make(map[string]AccessorValue),
   171  	}
   172  }
   173  
   174  // SetError clears the instances being used by this instance and sets the error to be returned
   175  // by Get with every call.  This error will be returned by Get until an update with one or more instances
   176  // occurs.
   177  func (la *layeredAccessor) SetError(err error) {
   178  	la.lock.Lock()
   179  	la.err = err
   180  	la.primary = nil
   181  	la.lock.Unlock()
   182  }
   183  
   184  // SetPrimary changes the instances used by this UpdateAccessor, clearing any error.  Note that Get will
   185  // still return an error if a is nil or empty.
   186  func (la *layeredAccessor) SetPrimary(a Accessor) {
   187  	la.lock.Lock()
   188  	la.err = nil
   189  	la.primary = a
   190  	la.lock.Unlock()
   191  }
   192  
   193  // SetPrimary changes the instances used by this UpdateAccessor, clearing any error.  Note that Get will
   194  // still return an error if a is nil or empty.
   195  func (la *layeredAccessor) SetFailOver(failover map[string]AccessorValue) {
   196  	la.lock.Lock()
   197  	la.failover = failover
   198  	la.lock.Unlock()
   199  }
   200  
   201  // Update sets both the instances and the Get error in a single, atomic call.
   202  func (la *layeredAccessor) UpdatePrimary(a Accessor, err error) {
   203  	la.lock.Lock()
   204  	la.err = err
   205  	la.primary = a
   206  	la.lock.Unlock()
   207  }
   208  
   209  // Update sets the instances, failovers and the Get error in a single, atomic call.
   210  func (la *layeredAccessor) UpdateFailOver(key string, a Accessor, err error) {
   211  	la.lock.Lock()
   212  	if la.failover == nil {
   213  		la.failover = make(map[string]AccessorValue)
   214  	}
   215  
   216  	la.failover[key] = AccessorValue{a, err}
   217  	la.lock.Unlock()
   218  }
   219  
   220  // Get hashes the key against the current set of instances to select an instance consistently.
   221  // This method will return an error if this instance isn't updated yet or has been updated with
   222  // no instances.
   223  func (la *layeredAccessor) Get(key []byte) (string, error) {
   224  	var instance string
   225  	var err error
   226  	la.lock.RLock()
   227  
   228  	routeErr := RouteError{}
   229  
   230  	switch {
   231  	case la.err != nil:
   232  		routeErr.addError(la.err)
   233  		instance, err = la.getFailOverInstance(key)
   234  		routeErr.addError(err)
   235  
   236  	case la.primary != nil:
   237  		instance, err = la.primary.Get(key)
   238  
   239  		if err != nil {
   240  			routeErr.addError(err)
   241  			instance, err = la.getFailOverInstance(key)
   242  			routeErr.addError(err)
   243  		}
   244  
   245  		if err := la.router.Route(instance); err != nil {
   246  			routeErr.addError(err)
   247  			tempInstance, err := la.getFailOverInstance(key)
   248  			if err != nil {
   249  				routeErr.addError(err)
   250  			} else {
   251  				instance = tempInstance
   252  			}
   253  		}
   254  	case la.failover != nil && len(la.failover) > 0:
   255  		instance, err = la.getFailOverInstance(key)
   256  		routeErr.addError(err)
   257  	default:
   258  		routeErr.addError(errNoInstances)
   259  	}
   260  
   261  	la.lock.RUnlock()
   262  	if routeErr.ErrChain.Empty() {
   263  		return instance, nil
   264  	}
   265  	routeErr.Instance = instance
   266  	return instance, routeErr
   267  }
   268  
   269  func (la *layeredAccessor) getFailOverInstance(key []byte) (instance string, err error) {
   270  	if la.failover == nil || len(la.failover) == 0 {
   271  		return "", errNoFailOvers
   272  	}
   273  
   274  	var order []string
   275  	dcs := make([]string, len(la.failover))
   276  	index := 0
   277  	for dc := range la.failover {
   278  		dcs[index] = dc
   279  		index++
   280  	}
   281  	if la.accessorQueue != nil {
   282  		order = la.accessorQueue.Order(dcs)
   283  	} else {
   284  		order = dcs
   285  	}
   286  
   287  	for _, dc := range order {
   288  		err = la.failover[dc].Err
   289  		if err != nil {
   290  			continue
   291  		}
   292  		instance, err = la.failover[dc].Accessor.Get(key)
   293  		if la.router == nil && err == nil {
   294  			return
   295  		} else if la.router != nil {
   296  			if tempErr := la.router.Route(instance); tempErr == nil {
   297  				return
   298  			}
   299  		}
   300  
   301  	}
   302  	return "", errFailOversFailed
   303  }
   304  
   305  type ErrorChain struct {
   306  	SubError error
   307  	Err      error
   308  }
   309  
   310  func (err ErrorChain) Error() string {
   311  	if err.SubError == nil {
   312  		return err.Err.Error()
   313  	}
   314  	if err.Err == nil {
   315  		panic("main Err can't be nil")
   316  	}
   317  	return fmt.Sprintf("%s(%s)", err.Err, err.SubError)
   318  }
   319  
   320  func (err ErrorChain) Empty() bool {
   321  	return err.Err == nil && err.SubError == nil
   322  }
   323  
   324  type RouteError struct {
   325  	ErrChain ErrorChain
   326  	Instance string
   327  }
   328  
   329  func (err *RouteError) addError(e error) {
   330  	if e != nil {
   331  		if err.ErrChain.Empty() {
   332  			err.ErrChain = ErrorChain{Err: e}
   333  		} else {
   334  			err.ErrChain = ErrorChain{Err: e, SubError: err.ErrChain}
   335  		}
   336  	}
   337  }
   338  
   339  func (err RouteError) Error() string {
   340  	return fmt.Sprintf("failed to route `%s`. reason: %s", err.Instance, err.ErrChain.Error())
   341  }