package org.apache.solr.request; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.atomic.AtomicLong; import org.apache.solr.request.uninverted.RamTermNumValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alimama.mdrill.utils.UniqConfig; public class BlockBufferPool<T> { private static Logger log = LoggerFactory.getLogger(BlockBufferPool.class); public static BlockBufferPool<Integer> INT_POOL=new BlockBufferPool<Integer>(); public static BlockBufferPool<Short> SHORT_POOL=new BlockBufferPool<Short>(); public static BlockBufferPool<Byte> BYTE_POOL=new BlockBufferPool<Byte>(); public static BlockBufferPool<Long> LONG_POOL=new BlockBufferPool<Long>(); public static BlockBufferPool<Double> DOUBLE_POOL=new BlockBufferPool<Double>(); private final static int intervalBits = 12; private final static int intervalMask = 0xffffffff >>> (32 - intervalBits); public final static int interval = 1 << intervalBits;// 1024*256 private AtomicLong mallocTimes = new AtomicLong(0l); private AtomicLong reusedTimes = new AtomicLong(0l); private ArrayList<BlockInterface<T>> freeByteBlocks = new ArrayList<BlockInterface<T>>(); public void recycleByteBlocks(BlockArray<T> data) { this.recycleByteBlocks(data,0); } public void recycleByteBlocks(BlockArray<T> data,int start) { synchronized (BlockBufferPool.this) { int allowsize = UniqConfig.getBlockBufferPoolSize() - this.freeByteBlocks.size(); final int size = data.data.length; for (int i = start; i < size; i++) { if (i < allowsize) { freeByteBlocks.add(data.data[i]); } data.data[i] = null; } data.data = null; data.size = 0; } } private BlockInterface<T> getByteBlock(CreateArr<T> c) { synchronized(BlockBufferPool.this) { final int size = freeByteBlocks.size(); final BlockInterface<T> b; if (0 == size) { b = c.create(); mallocTimes.incrementAndGet(); } else { b = freeByteBlocks.remove(size - 1); reusedTimes.incrementAndGet(); } return b; } } public BlockArray<T> calloc(int size, CreateArr<T> c, T init) { int block = size / interval + 1; BlockInterface<T>[] data = c.createBlocks(block); for (int i = 0; i < data.length; i++) { data[i]=getByteBlock(c); data[i].allset(init); } return new BlockArray<T>(data, size); } public BlockArray<T> reCalloc(BlockArray<T> old,int size, CreateArr<T> c, T init) { int block = size / interval + 1; BlockInterface<T>[] data = c.createBlocks(block); for (int i = 0; i < data.length; i++) { if(i<old.data.length) { data[i]=old.data[i]; }else{ data[i]=getByteBlock(c); data[i].allset(init); } } this.recycleByteBlocks(old,data.length); return new BlockArray<T>(data, size); } public void allset(BlockArray<T> last, CreateArr<T> c, T init) { for (int i = 0; i < last.data.length; i++) { last.data[i].allset(init); } } public static CreateArr<Byte> BYTE_CREATE = new CreateArr<Byte>() { @Override public BlockInterface<Byte> create() { return new BlockByte(); } @Override public BlockInterface<Byte>[] createBlocks(int size) { return new BlockByte[size]; } }; public static CreateArr<Integer> INT_CREATE = new CreateArr<Integer>() { @Override public BlockInterface<Integer> create() { return new BlockInteger(); } @Override public BlockInterface<Integer>[] createBlocks(int size) { return new BlockInteger[size]; } }; public static CreateArr<Short> SHORT_CREATE = new CreateArr<Short>() { @Override public BlockInterface<Short> create() { return new BlockShort(); } @Override public BlockInterface<Short>[] createBlocks(int size) { return new BlockShort[size]; } }; public static CreateArr<Long> LONG_CREATE = new CreateArr<Long>() { @Override public BlockInterface<Long> create() { return new BlockLong(); } @Override public BlockInterface<Long>[] createBlocks(int size) { return new BlockLong[size]; } }; public static CreateArr<Double> DOUBLE_CREATE = new CreateArr<Double>() { @Override public BlockInterface<Double> create() { return new BlockDouble(); } @Override public BlockInterface<Double>[] createBlocks(int size) { return new BlockDouble[size]; } }; public static interface CreateArr<T> { public BlockInterface<T> create(); public BlockInterface<T>[] createBlocks(int size); } private static class QuickArrayFillInt { private static int[] data_1=make(-1); private static int[] make(int def) { int[] data=new int[BlockBufferPool.interval]; Arrays.fill(data, def); return data; } public static void fill(int[] data,int v) { if(v==-1) { System.arraycopy(data_1, 0, data, 0,data_1.length); }else{ Arrays.fill(data, v); } } } private static class QuickArrayFillShort { private static short cmp=(short)-1; private static short[] data_1=make(cmp); private static short[] make(short def) { short[] data=new short[BlockBufferPool.interval]; Arrays.fill(data, def); return data; } public static void fill(short[] data,short v) { if(v==cmp) { System.arraycopy(data_1, 0, data, 0,data_1.length); }else{ Arrays.fill(data, v); } } } private static class QuickArrayFillByte { private static byte cmp=(byte)-1; private static byte[] data_1=make((byte)-1); private static byte[] make(byte def) { byte[] data=new byte[BlockBufferPool.interval]; Arrays.fill(data, def); return data; } public static void fill(byte[] data,byte v) { if(v==cmp) { System.arraycopy(data_1, 0, data, 0,data_1.length); }else{ Arrays.fill(data, v); } } } private static class QuickArrayFillLong { private static long[] data_1=make(-1l); private static long[] data_2=make(RamTermNumValue.TERMNUM_NAN_VALUE); private static long[] make(long def) { long[] data=new long[BlockBufferPool.interval]; Arrays.fill(data, def); return data; } public static void fill(long[] data,long v) { if(v==-1l) { System.arraycopy(data_1, 0, data, 0,data_1.length); }else if(v==RamTermNumValue.TERMNUM_NAN_VALUE) { System.arraycopy(data_2, 0, data, 0,data_2.length); }else{ Arrays.fill(data, v); } } } private static class QuickArrayFillDouble { private static double[] data_1=make(-1d); private static double dbl=(double)RamTermNumValue.TERMNUM_NAN_VALUE; private static double[] data_2=make(dbl); private static double[] make(double def) { double[] data=new double[BlockBufferPool.interval]; Arrays.fill(data, def); return data; } public static void fill(double[] data,double v) { if(v==-1l) { System.arraycopy(data_1, 0, data, 0,data_1.length); }else if(v==dbl) { System.arraycopy(data_2, 0, data, 0,data_2.length); }else{ Arrays.fill(data, v); } } } public static class BlockInteger implements BlockInterface<Integer> { private boolean hasInit=false; private int def=0; private int[] data=null; @Override public Integer get(int i) { if(hasInit) { return data[i]; } return def; } @Override public void set(int i, Integer v) { this.maybeinit(); data[i]=v; } @Override public void allset(Integer v) { this.def=v; hasInit=false; } private void maybeinit() { if(hasInit) { return ; } if(this.data==null) { data=new int[BlockBufferPool.interval]; } QuickArrayFillInt.fill(data, def); hasInit=true; } @Override public void replace(Integer a, Integer b) { if(this.hasInit) { for(int i=0;i<this.data.length;i++) { if(this.data[i]==a) { this.data[i]=b; } } }else if(this.def==a){ this.allset(b); } } @Override public void fillByInt(BlockInteger d,int skip){ if(d.hasInit) { if(this.hasInit) { for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=d.data[i]; } } }else{ data=new int[BlockBufferPool.interval]; for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=d.data[i]; }else{ data[i]=this.def; } } hasInit=true; } }else if(d.def!=skip){ this.allset(d.def); } } } public static class BlockShort implements BlockInterface<Short> { private boolean hasInit=false; private short def=0; short[] data=null; @Override public Short get(int i) { if(hasInit) { return data[i]; } return def; } @Override public void fillByInt(BlockInteger d,int skip){ if(d.hasInit) { if(this.hasInit) { for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(short)d.data[i]; } } }else{ data=new short[BlockBufferPool.interval]; for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(short)d.data[i]; }else{ data[i]=this.def; } } hasInit=true; } }else if(d.def!=skip){ this.allset((short)d.def); } } @Override public void set(int i, Short v) { this.maybeinit(); data[i]=v; } @Override public void allset(Short v) { this.def=v; hasInit=false; } private void maybeinit() { if(hasInit) { return ; } if(this.data==null) { data=new short[BlockBufferPool.interval]; } QuickArrayFillShort.fill(data, def); hasInit=true; } @Override public void replace(Short a, Short b) { if(this.hasInit) { for(int i=0;i<this.data.length;i++) { if(this.data[i]==a) { this.data[i]=b; } } }else if(this.def==a){ this.allset(b); } } } public static class BlockLong implements BlockInterface<Long> { private boolean hasInit=false; private long def=0; long[] data=null; @Override public Long get(int i) { if(hasInit) { return data[i]; } return def; } @Override public void fillByInt(BlockInteger d,int skip){ if(d.hasInit) { if(this.hasInit) { for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(long)d.data[i]; } } }else{ data=new long[BlockBufferPool.interval]; for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(long)d.data[i]; }else{ data[i]=this.def; } } hasInit=true; } }else if(d.def!=skip){ this.allset((long)d.def); } } @Override public void set(int i, Long v) { this.maybeinit(); data[i]=v; } @Override public void allset(Long v) { this.def=v; hasInit=false; } private void maybeinit() { if(hasInit) { return ; } if(this.data==null) { data=new long[BlockBufferPool.interval]; } QuickArrayFillLong.fill(data, def); hasInit=true; } @Override public void replace(Long a, Long b) { if(this.hasInit) { for(int i=0;i<this.data.length;i++) { if(this.data[i]==a) { this.data[i]=b; } } }else if(this.def==a){ this.allset(b); } } } public static class BlockDouble implements BlockInterface<Double> { private boolean hasInit=false; private double def=0; double[] data=null; @Override public Double get(int i) { if(hasInit) { return data[i]; } return def; } @Override public void set(int i, Double v) { this.maybeinit(); data[i]=v; } @Override public void allset(Double v) { this.def=v; hasInit=false; } @Override public void fillByInt(BlockInteger d,int skip){ if(d.hasInit) { if(this.hasInit) { for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(double)d.data[i]; } } }else{ data=new double[BlockBufferPool.interval]; for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(double)d.data[i]; }else{ data[i]=this.def; } } hasInit=true; } }else if(d.def!=skip){ this.allset((double)d.def); } } private void maybeinit() { if(hasInit) { return ; } if(this.data==null) { data=new double[BlockBufferPool.interval]; } QuickArrayFillDouble.fill(data, def); hasInit=true; } @Override public void replace(Double a, Double b) { if(this.hasInit) { for(int i=0;i<this.data.length;i++) { if(this.data[i]==a) { this.data[i]=b; } } }else if(this.def==a){ this.allset(b); } } } public static class BlockByte implements BlockInterface<Byte> { private boolean hasInit=false; private byte def=0; public byte[] data=null; @Override public Byte get(int i) { if(hasInit) { return data[i]; } return def; } @Override public void set(int i, Byte v) { this.maybeinit(); data[i]=v; } @Override public void fillByInt(BlockInteger d,int skip){ if(d.hasInit) { if(this.hasInit) { for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(byte)d.data[i]; } } }else{ data=new byte[BlockBufferPool.interval]; for(int i=0;i<d.data.length;i++) { if(d.data[i]!=skip) { data[i]=(byte)d.data[i]; }else{ data[i]=this.def; } } hasInit=true; } }else if(d.def!=skip){ this.allset((byte)d.def); } } @Override public void allset(Byte v) { this.def=v; hasInit=false; } private void maybeinit() { if(hasInit) { return ; } if(this.data==null) { data=new byte[BlockBufferPool.interval]; } QuickArrayFillByte.fill(data, def); hasInit=true; } @Override public void replace(Byte a, Byte b) { if(this.hasInit) { for(int i=0;i<this.data.length;i++) { if(this.data[i]==a) { this.data[i]=b; } } }else if(this.def==a){ this.allset(b); } } } public static interface BlockInterface<K>{ public K get(int i); public void set(int i,K v); public void allset(K v); public void fillByInt(BlockInteger d,int skip); public void replace(K a,K b); } public static class BlockArray<K> { private int size = 0; public BlockInterface<K>[] data; public BlockArray(BlockInterface<K>[] data, int size) { this.data = data; this.size = size; } public void fillByInt(BlockArray<Integer> d,int skip) { for(int i=0;i<d.data.length&&i<this.data.length;i++) { this.data[i].fillByInt((BlockInteger)(d.data[i]), skip); } } public void replace(K a,K b) { for(int i=0;i<this.data.length;i++) { this.data[i].replace(a,b); } } public K get(int i) { int block = i >>> intervalBits; int pos = i & intervalMask; return data[block].get(pos); } public void set(int i, K v) { int block = i >>> intervalBits; int pos = i & intervalMask; data[block].set(pos, v); } public int getSize() { return size; } public int getMemSize() { return Math.max(data.length*interval, size); } } }