File: token_store.go

package info (click to toggle)
golang-github-lucas-clemente-quic-go 0.54.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,312 kB
  • sloc: sh: 54; makefile: 7
file content (116 lines) | stat: -rw-r--r-- 2,572 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package quic

import (
	"sync"

	list "github.com/quic-go/quic-go/internal/utils/linkedlist"
)

type singleOriginTokenStore struct {
	tokens []*ClientToken
	len    int
	p      int
}

func newSingleOriginTokenStore(size int) *singleOriginTokenStore {
	return &singleOriginTokenStore{tokens: make([]*ClientToken, size)}
}

func (s *singleOriginTokenStore) Add(token *ClientToken) {
	s.tokens[s.p] = token
	s.p = s.index(s.p + 1)
	s.len = min(s.len+1, len(s.tokens))
}

func (s *singleOriginTokenStore) Pop() *ClientToken {
	s.p = s.index(s.p - 1)
	token := s.tokens[s.p]
	s.tokens[s.p] = nil
	s.len = max(s.len-1, 0)
	return token
}

func (s *singleOriginTokenStore) Len() int {
	return s.len
}

func (s *singleOriginTokenStore) index(i int) int {
	mod := len(s.tokens)
	return (i + mod) % mod
}

type lruTokenStoreEntry struct {
	key   string
	cache *singleOriginTokenStore
}

type lruTokenStore struct {
	mutex sync.Mutex

	m                map[string]*list.Element[*lruTokenStoreEntry]
	q                *list.List[*lruTokenStoreEntry]
	capacity         int
	singleOriginSize int
}

var _ TokenStore = &lruTokenStore{}

// NewLRUTokenStore creates a new LRU cache for tokens received by the client.
// maxOrigins specifies how many origins this cache is saving tokens for.
// tokensPerOrigin specifies the maximum number of tokens per origin.
func NewLRUTokenStore(maxOrigins, tokensPerOrigin int) TokenStore {
	return &lruTokenStore{
		m:                make(map[string]*list.Element[*lruTokenStoreEntry]),
		q:                list.New[*lruTokenStoreEntry](),
		capacity:         maxOrigins,
		singleOriginSize: tokensPerOrigin,
	}
}

func (s *lruTokenStore) Put(key string, token *ClientToken) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if el, ok := s.m[key]; ok {
		entry := el.Value
		entry.cache.Add(token)
		s.q.MoveToFront(el)
		return
	}

	if s.q.Len() < s.capacity {
		entry := &lruTokenStoreEntry{
			key:   key,
			cache: newSingleOriginTokenStore(s.singleOriginSize),
		}
		entry.cache.Add(token)
		s.m[key] = s.q.PushFront(entry)
		return
	}

	elem := s.q.Back()
	entry := elem.Value
	delete(s.m, entry.key)
	entry.key = key
	entry.cache = newSingleOriginTokenStore(s.singleOriginSize)
	entry.cache.Add(token)
	s.q.MoveToFront(elem)
	s.m[key] = elem
}

func (s *lruTokenStore) Pop(key string) *ClientToken {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	var token *ClientToken
	if el, ok := s.m[key]; ok {
		s.q.MoveToFront(el)
		cache := el.Value.cache
		token = cache.Pop()
		if cache.Len() == 0 {
			s.q.Remove(el)
			delete(s.m, key)
		}
	}
	return token
}