1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.buffer;
18
19 import io.netty.util.internal.StringUtil;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import static java.lang.Math.*;
27
28 final class PoolChunkList<T> implements PoolChunkListMetric {
29 private static final Iterator<PoolChunkMetric> EMPTY_METRICS = Collections.<PoolChunkMetric>emptyList().iterator();
30 private final PoolArena<T> arena;
31 private final PoolChunkList<T> nextList;
32 private final int minUsage;
33 private final int maxUsage;
34 private final int maxCapacity;
35 private PoolChunk<T> head;
36
37
38 private PoolChunkList<T> prevList;
39
40
41
42
43 PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) {
44 assert minUsage <= maxUsage;
45 this.arena = arena;
46 this.nextList = nextList;
47 this.minUsage = minUsage;
48 this.maxUsage = maxUsage;
49 maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
50 }
51
52
53
54
55
56 private static int calculateMaxCapacity(int minUsage, int chunkSize) {
57 minUsage = minUsage0(minUsage);
58
59 if (minUsage == 100) {
60
61 return 0;
62 }
63
64
65
66
67
68
69 return (int) (chunkSize * (100L - minUsage) / 100L);
70 }
71
72 void prevList(PoolChunkList<T> prevList) {
73 assert this.prevList == null;
74 this.prevList = prevList;
75 }
76
77 boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
78 if (head == null || normCapacity > maxCapacity) {
79
80
81 return false;
82 }
83
84 for (PoolChunk<T> cur = head;;) {
85 long handle = cur.allocate(normCapacity);
86 if (handle < 0) {
87 cur = cur.next;
88 if (cur == null) {
89 return false;
90 }
91 } else {
92 cur.initBuf(buf, handle, reqCapacity);
93 if (cur.usage() >= maxUsage) {
94 remove(cur);
95 nextList.add(cur);
96 }
97 return true;
98 }
99 }
100 }
101
102 boolean free(PoolChunk<T> chunk, long handle) {
103 chunk.free(handle);
104 if (chunk.usage() < minUsage) {
105 remove(chunk);
106
107 return move0(chunk);
108 }
109 return true;
110 }
111
112 private boolean move(PoolChunk<T> chunk) {
113 assert chunk.usage() < maxUsage;
114
115 if (chunk.usage() < minUsage) {
116
117 return move0(chunk);
118 }
119
120
121 add0(chunk);
122 return true;
123 }
124
125
126
127
128
129 private boolean move0(PoolChunk<T> chunk) {
130 if (prevList == null) {
131
132
133 assert chunk.usage() == 0;
134 return false;
135 }
136 return prevList.move(chunk);
137 }
138
139 void add(PoolChunk<T> chunk) {
140 if (chunk.usage() >= maxUsage) {
141 nextList.add(chunk);
142 return;
143 }
144 add0(chunk);
145 }
146
147
148
149
150 void add0(PoolChunk<T> chunk) {
151 chunk.parent = this;
152 if (head == null) {
153 head = chunk;
154 chunk.prev = null;
155 chunk.next = null;
156 } else {
157 chunk.prev = null;
158 chunk.next = head;
159 head.prev = chunk;
160 head = chunk;
161 }
162 }
163
164 private void remove(PoolChunk<T> cur) {
165 if (cur == head) {
166 head = cur.next;
167 if (head != null) {
168 head.prev = null;
169 }
170 } else {
171 PoolChunk<T> next = cur.next;
172 cur.prev.next = next;
173 if (next != null) {
174 next.prev = cur.prev;
175 }
176 }
177 }
178
179 @Override
180 public int minUsage() {
181 return minUsage0(minUsage);
182 }
183
184 @Override
185 public int maxUsage() {
186 return min(maxUsage, 100);
187 }
188
189 private static int minUsage0(int value) {
190 return max(1, value);
191 }
192
193 @Override
194 public Iterator<PoolChunkMetric> iterator() {
195 synchronized (arena) {
196 if (head == null) {
197 return EMPTY_METRICS;
198 }
199 List<PoolChunkMetric> metrics = new ArrayList<PoolChunkMetric>();
200 for (PoolChunk<T> cur = head;;) {
201 metrics.add(cur);
202 cur = cur.next;
203 if (cur == null) {
204 break;
205 }
206 }
207 return metrics.iterator();
208 }
209 }
210
211 @Override
212 public String toString() {
213 StringBuilder buf = new StringBuilder();
214 synchronized (arena) {
215 if (head == null) {
216 return "none";
217 }
218
219 for (PoolChunk<T> cur = head;;) {
220 buf.append(cur);
221 cur = cur.next;
222 if (cur == null) {
223 break;
224 }
225 buf.append(StringUtil.NEWLINE);
226 }
227 }
228 return buf.toString();
229 }
230
231 void destroy(PoolArena<T> arena) {
232 PoolChunk<T> chunk = head;
233 while (chunk != null) {
234 arena.destroyChunk(chunk);
235 chunk = chunk.next;
236 }
237 head = null;
238 }
239 }