github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/token_store.go (about)

     1  package quic
     2  
     3  import (
     4  	"sync"
     5  
     6  	list "github.com/daeuniverse/quic-go/internal/utils/linkedlist"
     7  )
     8  
     9  type singleOriginTokenStore struct {
    10  	tokens []*ClientToken
    11  	len    int
    12  	p      int
    13  }
    14  
    15  func newSingleOriginTokenStore(size int) *singleOriginTokenStore {
    16  	return &singleOriginTokenStore{tokens: make([]*ClientToken, size)}
    17  }
    18  
    19  func (s *singleOriginTokenStore) Add(token *ClientToken) {
    20  	s.tokens[s.p] = token
    21  	s.p = s.index(s.p + 1)
    22  	s.len = min(s.len+1, len(s.tokens))
    23  }
    24  
    25  func (s *singleOriginTokenStore) Pop() *ClientToken {
    26  	s.p = s.index(s.p - 1)
    27  	token := s.tokens[s.p]
    28  	s.tokens[s.p] = nil
    29  	s.len = max(s.len-1, 0)
    30  	return token
    31  }
    32  
    33  func (s *singleOriginTokenStore) Len() int {
    34  	return s.len
    35  }
    36  
    37  func (s *singleOriginTokenStore) index(i int) int {
    38  	mod := len(s.tokens)
    39  	return (i + mod) % mod
    40  }
    41  
    42  type lruTokenStoreEntry struct {
    43  	key   string
    44  	cache *singleOriginTokenStore
    45  }
    46  
    47  type lruTokenStore struct {
    48  	mutex sync.Mutex
    49  
    50  	m                map[string]*list.Element[*lruTokenStoreEntry]
    51  	q                *list.List[*lruTokenStoreEntry]
    52  	capacity         int
    53  	singleOriginSize int
    54  }
    55  
    56  var _ TokenStore = &lruTokenStore{}
    57  
    58  // NewLRUTokenStore creates a new LRU cache for tokens received by the client.
    59  // maxOrigins specifies how many origins this cache is saving tokens for.
    60  // tokensPerOrigin specifies the maximum number of tokens per origin.
    61  func NewLRUTokenStore(maxOrigins, tokensPerOrigin int) TokenStore {
    62  	return &lruTokenStore{
    63  		m:                make(map[string]*list.Element[*lruTokenStoreEntry]),
    64  		q:                list.New[*lruTokenStoreEntry](),
    65  		capacity:         maxOrigins,
    66  		singleOriginSize: tokensPerOrigin,
    67  	}
    68  }
    69  
    70  func (s *lruTokenStore) Put(key string, token *ClientToken) {
    71  	s.mutex.Lock()
    72  	defer s.mutex.Unlock()
    73  
    74  	if el, ok := s.m[key]; ok {
    75  		entry := el.Value
    76  		entry.cache.Add(token)
    77  		s.q.MoveToFront(el)
    78  		return
    79  	}
    80  
    81  	if s.q.Len() < s.capacity {
    82  		entry := &lruTokenStoreEntry{
    83  			key:   key,
    84  			cache: newSingleOriginTokenStore(s.singleOriginSize),
    85  		}
    86  		entry.cache.Add(token)
    87  		s.m[key] = s.q.PushFront(entry)
    88  		return
    89  	}
    90  
    91  	elem := s.q.Back()
    92  	entry := elem.Value
    93  	delete(s.m, entry.key)
    94  	entry.key = key
    95  	entry.cache = newSingleOriginTokenStore(s.singleOriginSize)
    96  	entry.cache.Add(token)
    97  	s.q.MoveToFront(elem)
    98  	s.m[key] = elem
    99  }
   100  
   101  func (s *lruTokenStore) Pop(key string) *ClientToken {
   102  	s.mutex.Lock()
   103  	defer s.mutex.Unlock()
   104  
   105  	var token *ClientToken
   106  	if el, ok := s.m[key]; ok {
   107  		s.q.MoveToFront(el)
   108  		cache := el.Value.cache
   109  		token = cache.Pop()
   110  		if cache.Len() == 0 {
   111  			s.q.Remove(el)
   112  			delete(s.m, key)
   113  		}
   114  	}
   115  	return token
   116  }