Commit 8f47d36
authored
attributes: Replace internal map with linked list (#8933)
Fixes: #8921
This PR replaces the underlying `map[any]any` implementation in the
`Attributes` struct with a singly linked list.
Because `Attributes` are immutable, the previous implementation required
a complete allocation and map copy every time `WithValue` was called.
Since this data structure is primarily used in the control plane and
typically holds a small number of values (10-20 at most), optimizing for
memory is significantly more valuable than optimizing for lookup speed.
By switching to a persistent linked-list , appending a new value becomes
a highly efficient operation. `WithValue` now simply prepends a new node
that points to the previous state, entirely eliminating the need to copy
existing elements. Shadowing is handled naturally by returning the first
match found during traversal. This approach is very similar to the
implementation of
[context.WithValue](https://cs.opensource.google/go/go/+/refs/tags/go1.26.0:src/context/context.go;l=727;drc=1a53ce9734c0b2a3e2a9814e75949ea77a978143).
### Complexity Comparison
The following table breaks down the time and memory complexity of the
`Attributes` operations, where $N$ is the number of keys.
| Operation | Previous Time | Previous Space | New Time | New Space |
Notes on New Implementation |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **`New`** | $O(1)$ | $O(1)$ | $O(1)$ | $O(1)$ | Allocates a single
head node. |
| **`WithValue`** | $O(N)$ | $O(N)$ | $O(1)$ | $O(1)$ | **Highly
Optimized:** Merely prepends a new node to the existing list instead of
copying a full map. |
| **`Value`** (Lookup) | $O(1)$ | $O(1)$ | $O(N)$ | $O(1)$ | Requires a
linear scan. For $N \le 20$, this overhead is negligible. |
| **`Equal`** | $O(N)$ | $O(1)$ | $O(N)$ | $O(N)$ | Allocates temporary
maps to track shadowed keys and compare list contents. |
### Benchmark
The benchmark added compares the memory usage for storing 10 attributes
in 50 endpoints. It shows a 86% reduction is memory utilization.
```sh
goos: linux
goarch: amd64
pkg: google.golang.org/grpc/attributes
cpu: Intel(R) Xeon(R) CPU @ 2.60GHz
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
WithValue-48 168.26µ ± 0% 15.53µ ± 1% -90.77% (p=0.000 n=10)
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
WithValue-48 200.00Ki ± 0% 23.44Ki ± 0% -88.28% (p=0.000 n=10)
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
WithValue-48 1700.0 ± 0% 500.0 ± 0% -70.59% (p=0.000 n=10)
```
RELEASE NOTES:
* attributes: Optimize memory utilization from $O(n)$ to $O(1)$.1 parent 22e1ee8 commit 8f47d36
2 files changed
Lines changed: 137 additions & 43 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
| 31 | + | |
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
| |||
37 | 39 | | |
38 | 40 | | |
39 | 41 | | |
40 | | - | |
| 42 | + | |
| 43 | + | |
41 | 44 | | |
42 | 45 | | |
43 | 46 | | |
44 | 47 | | |
45 | | - | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
46 | 52 | | |
47 | 53 | | |
48 | 54 | | |
49 | 55 | | |
50 | | - | |
51 | | - | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
52 | 65 | | |
53 | | - | |
54 | | - | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
55 | 70 | | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | 71 | | |
63 | 72 | | |
64 | 73 | | |
65 | 74 | | |
66 | 75 | | |
67 | | - | |
68 | | - | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
69 | 80 | | |
70 | | - | |
| 81 | + | |
71 | 82 | | |
72 | 83 | | |
73 | 84 | | |
| |||
83 | 94 | | |
84 | 95 | | |
85 | 96 | | |
86 | | - | |
87 | | - | |
| 97 | + | |
| 98 | + | |
88 | 99 | | |
89 | | - | |
90 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
91 | 106 | | |
92 | 107 | | |
93 | 108 | | |
| |||
101 | 116 | | |
102 | 117 | | |
103 | 118 | | |
104 | | - | |
| 119 | + | |
105 | 120 | | |
106 | 121 | | |
107 | 122 | | |
| |||
110 | 125 | | |
111 | 126 | | |
112 | 127 | | |
113 | | - | |
| 128 | + | |
114 | 129 | | |
115 | 130 | | |
116 | 131 | | |
117 | | - | |
| 132 | + | |
118 | 133 | | |
119 | 134 | | |
120 | 135 | | |
| |||
139 | 154 | | |
140 | 155 | | |
141 | 156 | | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
| 98 | + | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
106 | 156 | | |
107 | | - | |
108 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
109 | 169 | | |
110 | 170 | | |
111 | 171 | | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
124 | 176 | | |
125 | | - | |
126 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
127 | 188 | | |
128 | 189 | | |
0 commit comments