1 4 package com.tc.bytes; 5 6 import com.tc.exception.TCRuntimeException; 7 import com.tc.logging.LossyTCLogger; 8 import com.tc.logging.TCLogger; 9 import com.tc.logging.TCLogging; 10 import com.tc.util.runtime.IOFlavor; 11 12 import java.util.LinkedList ; 13 14 21 public class TCByteBufferFactory { 22 private static final int WARN_THRESHOLD = 10485760; 24 25 private static final boolean disablePooling = false; 26 27 private static final TCByteBufferFactoryIF factory; 28 29 private static final LinkedList directFreePool = new LinkedList (); 30 31 private static final LinkedList nonDirectFreePool = new LinkedList (); 32 33 private static final int DEFAULT_FIXED_SIZE = 4096; 35 private static final int MAX_POOL_SIZE = 2048 * 4; 36 37 private static final int fixedBufferSize = DEFAULT_FIXED_SIZE; 39 40 private static final boolean useNIO; 41 42 private static final TCByteBuffer[] EMPTY_BB_ARRAY = new TCByteBuffer[] {}; 43 44 private static final TCLogger logger = TCLogging.getLogger(TCByteBufferFactory.class); 45 private static final TCLogger lossyLogger = new LossyTCLogger(logger); 46 47 private static final TCByteBuffer ZERO_BYTE_BUFFER; 48 49 static { 50 Class factoryClass = null; 51 useNIO = IOFlavor.isNioAvailable(); 52 53 try { 54 if (useNIO) { 55 factoryClass = Class.forName("com.tc.bytes.TCByteBufferFactoryJDK14"); 56 } else { 57 factoryClass = Class.forName("com.tc.bytes.TCByteBufferFactoryJDK13"); 58 } 59 } catch (ClassNotFoundException cfe) { 60 throw new TCRuntimeException("internal error", cfe); 61 } 62 63 try { 64 factory = (TCByteBufferFactoryIF) factoryClass.newInstance(); 65 } catch (InstantiationException ie) { 66 throw new TCRuntimeException("internal error", ie); 67 } catch (IllegalAccessException iae) { 68 throw new TCRuntimeException("internal error", iae); 69 } 70 ZERO_BYTE_BUFFER = factory.wrap(new byte[0]); 71 } 72 73 private static TCByteBuffer createNewInstance(boolean direct, int capacity, int index, int totalCount) { 74 try { 75 TCByteBuffer rv = factory.getInstance(capacity, direct); 76 return rv; 80 } catch (OutOfMemoryError oome) { 81 logger.error("OOME trying to allocate " + (direct ? "direct" : "non-direct") + " buffer of size " + capacity 83 + " (index " + index + " of count " + totalCount + ")"); 84 throw oome; 85 } 86 } 87 88 98 public static TCByteBuffer getInstance(final boolean direct, int size) { 99 100 if (size > WARN_THRESHOLD) { 101 logger.warn("Asking for a large amount of memory: " + size + " bytes"); 102 } 103 if (size < 0) { throw new IllegalArgumentException ("Requested length cannot be less than zero"); } 104 if(size == 0) { return ZERO_BYTE_BUFFER; } 105 106 if (disablePooling || size > fixedBufferSize) { 107 return createNewInstance(direct, size); 108 } else { 109 return getFromPoolOrCreate(direct); 110 } 111 } 112 113 private static TCByteBuffer getFromPoolOrCreate(final boolean direct) { 114 return getFromPoolOrCreate(direct, 0, 1); 115 } 116 117 private static TCByteBuffer getFromPoolOrCreate(boolean direct, int i, int numBuffers) { 118 119 TCByteBuffer buffer = getFromPool(direct); 120 if (null == buffer) { 121 buffer = createNewInstance(direct, fixedBufferSize, i, numBuffers); 122 } 123 return buffer; 124 } 125 126 private static TCByteBuffer createNewInstance(boolean direct, int bufferSize) { 127 return createNewInstance(direct, bufferSize, 0, 1); 128 } 129 130 140 public static TCByteBuffer[] getFixedSizedInstancesForLength(final boolean direct, final int length) { 141 if (length > WARN_THRESHOLD) { 142 logger.warn("Asking for a large amount of memory: " + length + " bytes"); 143 } 144 145 if (length < 0) { throw new IllegalArgumentException ("Requested length cannot be less than zero"); } 146 147 if (length == 0) { return EMPTY_BB_ARRAY; } 148 149 int numBuffers = length / fixedBufferSize; 150 if ((length % fixedBufferSize) != 0) { 151 numBuffers++; 152 } 153 154 TCByteBuffer rv[] = new TCByteBuffer[numBuffers]; 155 156 if (disablePooling) { 157 for (int i = 0; i < numBuffers; i++) { 158 rv[i] = createNewInstance(direct, fixedBufferSize, i, numBuffers); 159 } 160 } else { for (int i = 0; i < numBuffers; i++) { 162 rv[i] = getFromPoolOrCreate(direct, i, numBuffers); 163 } 164 } 165 166 TCByteBuffer lastBuffer = rv[rv.length - 1]; 168 lastBuffer.limit(lastBuffer.capacity() - ((numBuffers * fixedBufferSize) - length)); 169 170 172 return rv; 173 } 174 175 private static TCByteBuffer getFromPool(boolean direct) { 176 if (disablePooling) return null; 177 if (direct) { 178 synchronized (directFreePool) { 179 return directFreePool.size() > 0 ? (TCByteBuffer) directFreePool.removeFirst() : null; 180 } 181 } else { 182 synchronized (nonDirectFreePool) { 183 return nonDirectFreePool.size() > 0 ? (TCByteBuffer) nonDirectFreePool.removeFirst() : null; 184 } 185 } 186 } 187 188 public static void returnBuffers(TCByteBuffer buffers[]) { 189 if (disablePooling) { return; } 190 191 for (int i = 0; i < buffers.length; i++) { 192 TCByteBuffer buf = buffers[i]; 193 returnBuffer(buf); 194 } 195 } 196 197 public static void returnBuffer(TCByteBuffer buf) { 198 if (disablePooling) { return; } 199 200 if (buf.capacity() == fixedBufferSize) { 201 if (buf.isDirect()) { 202 synchronized (directFreePool) { 203 if (directFreePool.size() < MAX_POOL_SIZE) { 204 directFreePool.addLast(buf); 206 } 207 } 208 } else { 209 synchronized (nonDirectFreePool) { 210 if (nonDirectFreePool.size() < MAX_POOL_SIZE) { 211 nonDirectFreePool.addLast(buf); 213 } 214 else { 215 lossyLogger.info("MAX POOL Size of " + nonDirectFreePool.size() + " reached !"); 216 } 217 } 218 } 219 } 220 } 221 222 public static TCByteBuffer wrap(byte[] buf) { 223 return factory.wrap(buf); 224 } 225 226 public static TCByteBuffer copyAndWrap(byte[] buf) { 227 TCByteBuffer rv = null; 228 if (buf != null) { 229 rv = getInstance(false, buf.length); 230 rv.put(buf).rewind(); 231 } else { 232 rv = getInstance(false, 0); 233 } 234 return rv; 235 } 236 237 } | Popular Tags |