package org.apache.hadoop.mapred; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class CachePool { public static class CachePoolFullException extends IOException { CachePoolFullException(String s) { super(s); } } public static class CacheUnit extends ByteArrayInputStream { static int cap = 0; private boolean isLast = false; public CacheUnit() { super(new byte[cap]); count = 0; } public int write(InputStream in) throws IOException { if (count >= buf.length) { return 0; } int res = in.read(buf, count, buf.length - count); if (res < 0) { return res; } count += res; return res; } public int write(byte b[], int off, int len){ len = Math.min(len, buf.length - count); System.arraycopy(b, off, buf, count, len); count += len; return len; } public void writeFile(OutputStream out) throws IOException { out.write(buf, mark, count); } public boolean write(int b){ if (count >= buf.length) { return false; } buf[count++] = (byte)b; return true; } public int getPos() { return pos; } public int getLen() { return count; } public void reinit(){ count = 0; mark = 0; pos = 0; isLast = false; } public boolean isLast() { return isLast; } public void setLast() { isLast = true; } } static private long upLine; private List<CacheUnit> pool = new LinkedList<CacheUnit>(); private int busyNum = 0; static CachePool cp = null; static public void init(long up, int unitSize) { upLine = up; CacheUnit.cap = unitSize; } public static CachePool get() { if (cp == null) { cp = new CachePool(); } return cp; } public synchronized List<CacheUnit> getUnits(int num) throws CachePoolFullException { List<CacheUnit> res = new ArrayList<CacheUnit>(num); if (pool.size() >= num) { busyNum += num; res.addAll(pool.subList(0, num)); pool.subList(0, num).clear(); return res; } else if ((busyNum + pool.size()) * CacheUnit.cap >= upLine){ throw new CachePoolFullException("current cache size " + (busyNum * CacheUnit.cap) + " exceed upline " + upLine); } else { busyNum += num; for (int i = 0; i < num; i++) { res.add(new CacheUnit()); } return res; } } public synchronized CacheUnit getUnit() throws CachePoolFullException { if (!pool.isEmpty()) { busyNum++; return pool.remove(0); } else if ((busyNum + pool.size()) * CacheUnit.cap >= upLine){ throw new CachePoolFullException("current cache size " + (busyNum * CacheUnit.cap) + " exceed upline " + upLine); } else { busyNum++; return new CacheUnit(); } } public synchronized void returnUnit(CacheUnit cu) { busyNum--; cu.reinit(); pool.add(cu); } public synchronized void returnUnit(List<CacheUnit> l) { busyNum -= l.size(); for (CacheUnit cu : l) { cu.reinit(); pool.add(cu); } } }