package org.jgroups.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Provides a pool of output streams so we can do lock striping and have faster marshalling this way.
 * @author Bela Ban
 */
@Deprecated
public class MarshallerPool {
    final int pool_size;     // number of pools
    final int INITIAL_SIZE;  // initial size of each pool

    final ExposedByteArrayOutputStream[] outs;
    final ExposedDataOutputStream[] outputs;
    final Lock[] locks;

    public MarshallerPool(int pool_size, int initial_size) {
        this.pool_size=pool_size;
        INITIAL_SIZE=initial_size;

        outs=new ExposedByteArrayOutputStream[pool_size];
        for(int i=0; i < outs.length; i++)
            outs[i]=new ExposedByteArrayOutputStream(INITIAL_SIZE);

        outputs=new ExposedDataOutputStream[pool_size];
        for(int i=0; i < outputs.length; i++)
            outputs[i]=new ExposedDataOutputStream(outs[i]);

        locks=new Lock[pool_size];
        for(int i=0; i < locks.length; i++)
            locks[i]=new ReentrantLock();
    }


    /**
     * Returns a random output stream. To use it, the lock needs to be acquired.
     * When done, it also needs to be released again.
     * @return
     */
    public Triple<Lock,ExposedByteArrayOutputStream,ExposedDataOutputStream> getOutputStream() {
        int index=(int)Util.random(pool_size) -1;
        return new Triple<Lock,ExposedByteArrayOutputStream,ExposedDataOutputStream>(locks[index], outs[index], outputs[index]);
    }


    public int[] getCapacities() {
        int[] retval=new int[pool_size];
        for(int i=0; i < outs.length; i++)
            retval[i]=outs[i].getCapacity();
        return retval;
    }

    /** Closes all output streams. This releases the memory held by them */
    public void close() {
        for(int i=0; i < pool_size; i++) {
            try {
                locks[i].tryLock(2000, TimeUnit.MILLISECONDS);
                Util.close(outputs[i]);
            }
            catch(InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            finally {
                if(((ReentrantLock)locks[i]).isHeldByCurrentThread())
                    locks[i].unlock();
            }
        }
    }


}
