mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 12:37:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: MPL-2.0
 | 
						|
 | 
						|
package physical
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"math/rand"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	log "github.com/hashicorp/go-hclog"
 | 
						|
	uberAtomic "go.uber.org/atomic"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	// DefaultJitterPercent is used if no cache size is specified for NewCache
 | 
						|
	DefaultJitterPercent = 20
 | 
						|
)
 | 
						|
 | 
						|
// LatencyInjector is used to add latency into underlying physical requests
 | 
						|
type LatencyInjector struct {
 | 
						|
	logger        log.Logger
 | 
						|
	backend       Backend
 | 
						|
	latency       *uberAtomic.Duration
 | 
						|
	jitterPercent int
 | 
						|
	randomLock    *sync.Mutex
 | 
						|
	random        *rand.Rand
 | 
						|
}
 | 
						|
 | 
						|
// TransactionalLatencyInjector is the transactional version of the latency
 | 
						|
// injector
 | 
						|
type TransactionalLatencyInjector struct {
 | 
						|
	*LatencyInjector
 | 
						|
	Transactional
 | 
						|
}
 | 
						|
 | 
						|
// Verify LatencyInjector satisfies the correct interfaces
 | 
						|
var (
 | 
						|
	_ Backend       = (*LatencyInjector)(nil)
 | 
						|
	_ Transactional = (*TransactionalLatencyInjector)(nil)
 | 
						|
)
 | 
						|
 | 
						|
// NewLatencyInjector returns a wrapped physical backend to simulate latency
 | 
						|
func NewLatencyInjector(b Backend, latency time.Duration, jitter int, logger log.Logger) *LatencyInjector {
 | 
						|
	if jitter < 0 || jitter > 100 {
 | 
						|
		jitter = DefaultJitterPercent
 | 
						|
	}
 | 
						|
	logger.Info("creating latency injector")
 | 
						|
 | 
						|
	return &LatencyInjector{
 | 
						|
		logger:        logger,
 | 
						|
		backend:       b,
 | 
						|
		latency:       uberAtomic.NewDuration(latency),
 | 
						|
		jitterPercent: jitter,
 | 
						|
		randomLock:    new(sync.Mutex),
 | 
						|
		random:        rand.New(rand.NewSource(int64(time.Now().Nanosecond()))),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewTransactionalLatencyInjector creates a new transactional LatencyInjector
 | 
						|
// jitter is the random percent that latency will vary between.
 | 
						|
// For example, if you specify latency = 50ms and jitter = 20, then for any
 | 
						|
// given operation, the latency will be 50ms +- 10ms (20% of 50), or between 40 and 60ms.
 | 
						|
func NewTransactionalLatencyInjector(b Backend, latency time.Duration, jitter int, logger log.Logger) *TransactionalLatencyInjector {
 | 
						|
	return &TransactionalLatencyInjector{
 | 
						|
		LatencyInjector: NewLatencyInjector(b, latency, jitter, logger),
 | 
						|
		Transactional:   b.(Transactional),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (l *LatencyInjector) SetLatency(latency time.Duration) {
 | 
						|
	l.logger.Info("Changing backend latency", "latency", latency)
 | 
						|
	l.latency.Store(latency)
 | 
						|
}
 | 
						|
 | 
						|
func (l *LatencyInjector) addLatency() {
 | 
						|
	// Calculate a value between 1 +- jitter%
 | 
						|
	percent := 100
 | 
						|
	if l.jitterPercent > 0 {
 | 
						|
		min := 100 - l.jitterPercent
 | 
						|
		max := 100 + l.jitterPercent
 | 
						|
		l.randomLock.Lock()
 | 
						|
		percent = l.random.Intn(max-min) + min
 | 
						|
		l.randomLock.Unlock()
 | 
						|
	}
 | 
						|
	latencyDuration := time.Duration(int(l.latency.Load()) * percent / 100)
 | 
						|
	time.Sleep(latencyDuration)
 | 
						|
}
 | 
						|
 | 
						|
// Put is a latent put request
 | 
						|
func (l *LatencyInjector) Put(ctx context.Context, entry *Entry) error {
 | 
						|
	l.addLatency()
 | 
						|
	return l.backend.Put(ctx, entry)
 | 
						|
}
 | 
						|
 | 
						|
// Get is a latent get request
 | 
						|
func (l *LatencyInjector) Get(ctx context.Context, key string) (*Entry, error) {
 | 
						|
	l.addLatency()
 | 
						|
	return l.backend.Get(ctx, key)
 | 
						|
}
 | 
						|
 | 
						|
// Delete is a latent delete request
 | 
						|
func (l *LatencyInjector) Delete(ctx context.Context, key string) error {
 | 
						|
	l.addLatency()
 | 
						|
	return l.backend.Delete(ctx, key)
 | 
						|
}
 | 
						|
 | 
						|
// List is a latent list request
 | 
						|
func (l *LatencyInjector) List(ctx context.Context, prefix string) ([]string, error) {
 | 
						|
	l.addLatency()
 | 
						|
	return l.backend.List(ctx, prefix)
 | 
						|
}
 | 
						|
 | 
						|
// Transaction is a latent transaction request
 | 
						|
func (l *TransactionalLatencyInjector) Transaction(ctx context.Context, txns []*TxnEntry) error {
 | 
						|
	l.addLatency()
 | 
						|
	return l.Transactional.Transaction(ctx, txns)
 | 
						|
}
 |