View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.buffer;
18  
19  import io.netty.util.internal.StringUtil;
20  
21  final class PoolChunkList<T> {
22      private final PoolArena<T> arena;
23      private final PoolChunkList<T> nextList;
24      PoolChunkList<T> prevList;
25  
26      private final int minUsage;
27      private final int maxUsage;
28  
29      private PoolChunk<T> head;
30  
31      // TODO: Test if adding padding helps under contention
32      //private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
33  
34      PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage) {
35          this.arena = arena;
36          this.nextList = nextList;
37          this.minUsage = minUsage;
38          this.maxUsage = maxUsage;
39      }
40  
41      boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
42          if (head == null) {
43              return false;
44          }
45  
46          for (PoolChunk<T> cur = head;;) {
47              long handle = cur.allocate(normCapacity);
48              if (handle < 0) {
49                  cur = cur.next;
50                  if (cur == null) {
51                      return false;
52                  }
53              } else {
54                  cur.initBuf(buf, handle, reqCapacity);
55                  if (cur.usage() >= maxUsage) {
56                      remove(cur);
57                      nextList.add(cur);
58                  }
59                  return true;
60              }
61          }
62      }
63  
64      void free(PoolChunk<T> chunk, long handle) {
65          chunk.free(handle);
66          if (chunk.usage() < minUsage) {
67              remove(chunk);
68              if (prevList == null) {
69                  assert chunk.usage() == 0;
70                  arena.destroyChunk(chunk);
71              } else {
72                  prevList.add(chunk);
73              }
74          }
75      }
76  
77      void add(PoolChunk<T> chunk) {
78          if (chunk.usage() >= maxUsage) {
79              nextList.add(chunk);
80              return;
81          }
82  
83          chunk.parent = this;
84          if (head == null) {
85              head = chunk;
86              chunk.prev = null;
87              chunk.next = null;
88          } else {
89              chunk.prev = null;
90              chunk.next = head;
91              head.prev = chunk;
92              head = chunk;
93          }
94      }
95  
96      private void remove(PoolChunk<T> cur) {
97          if (cur == head) {
98              head = cur.next;
99              if (head != null) {
100                 head.prev = null;
101             }
102         } else {
103             PoolChunk<T> next = cur.next;
104             cur.prev.next = next;
105             if (next != null) {
106                 next.prev = cur.prev;
107             }
108         }
109     }
110 
111     @Override
112     public String toString() {
113         if (head == null) {
114             return "none";
115         }
116 
117         StringBuilder buf = new StringBuilder();
118         for (PoolChunk<T> cur = head;;) {
119             buf.append(cur);
120             cur = cur.next;
121             if (cur == null) {
122                 break;
123             }
124             buf.append(StringUtil.NEWLINE);
125         }
126 
127         return buf.toString();
128     }
129 }