Package com.dp.nebula.wormhole.engine.storage

Source Code of com.dp.nebula.wormhole.engine.storage.DoubleQueue

package com.dp.nebula.wormhole.engine.storage;

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

import com.dp.nebula.wormhole.common.interfaces.ILine;

public class DoubleQueue extends StorageQueue
{
  private static final long serialVersionUID = -7821124845002857361L;

  private int lineLimit;
 
  //private int byteLimit;

  //the real double queues
  private final ILine[] itemsA;
 
  private final ILine[] itemsB;

  /**
   * writeArray : in reader's eyes, reader get data from data source and write data to this line array.
   * readArray : in writer's eyes, writer put data to data destination from this line array.
   * readCount and writeCount are counters of these two array
   * readPosition and writePosition is the position now been read or wrote
   *
   * Because of the doubleQueue mechanism, the two line will exchange when time is suitable.
   *
   */
  private ILine[] writeArray, readArray;
 
  private volatile int writeCount, readCount;
 
  private int  writePosition, readPosition;

  private ReentrantLock readLock, writeLock;
   
  private Condition notFull;
 
  private Condition awake;
 
  private boolean closed = false;
 
  private int spillSize = 0;

  private long lineRx = 0;
 
  private long lineTx = 0;
 
  /**  received byte number of data from data source(eg:httpreader load data from httpurl) */
  private long byteRx = 0;

  /**
   * Get info of line number in {@link DoubleQueue} space.
   *
   * @return
   *       Information of line number.
   *
   */
  public String info() {
    return "Read " + lineRx + " | Write " + lineTx + " |";
  }

  /**
   * Use the two parameters to construct a {@link DoubleQueue} which hold the swap areas.
   *
   * @param  lineLimit
   *       Limit of the line number the {@link DoubleQueue} can hold.
   *
   * @param  byteLimit
   *       Limit of the bytes the {@link DoubleQueue} can hold.
   *
   */
  public DoubleQueue(int lineLimit, int byteLimit) {
    if (lineLimit <= 0 || byteLimit <= 0) {
      throw new IllegalArgumentException(
          "Queue initial capacity can't less than 0!");
    }
    this.lineLimit = lineLimit;
//    this.byteLimit = byteLimit;
    itemsA = new ILine[lineLimit];
    itemsB = new ILine[lineLimit];

    readLock = new ReentrantLock();
    writeLock = new ReentrantLock();

    notFull = writeLock.newCondition();
    awake = writeLock.newCondition();

    readArray = itemsA;
    writeArray = itemsB;
    spillSize = lineLimit * 8 / 10;
  }

  /**
   * Get line number of the {@link DoubleQueue}
   *
   * @return  lineLimit
   *       Limit of the line number the {@link DoubleQueue} can hold.
   *
   */
  public int getLineLimit() {
    return lineLimit;
  }

  /**
   * Set line number of the {@link DoubleQueue}.
   *
   * @param  capacity
   *       Limit of the line number the {@link DoubleQueue} can hold.
   *
   */
  public void setLineLimit(int capacity) {
    this.lineLimit = capacity;
  }

  /**
   * Insert one line of record to a apace which buffers the swap data.
   *
   * @param  line
   *       The inserted line.
   *
   */
  private void insert(ILine line) {
    writeArray[writePosition] = line;
    ++writePosition;
    ++writeCount;
    ++lineRx;
    byteRx += line.length();
  }

  /**
   * Insert a line array(appointed the limit of array size) of data to a apace which buffers the swap data.
   *
   * @param lines
   *       Inserted line array.
   *
   * @param size
   *       Limit of inserted size of the line array.
   *
   */
  private void insert(ILine[] lines, int size) {
    for (int i = 0; i < size; ++i) {
      writeArray[writePosition] = lines[i];
      ++writePosition;
      ++writeCount;
      ++lineRx;
      byteRx += lines[i].length();
    }
  }

  /**
   * Extract one line of record from the space which contains current data.
   *
   * @return  line
   *       A line of data.
   *
   */
  private ILine extract() {
    ILine e = readArray[readPosition];
    readArray[readPosition] = null;
    ++readPosition;
    --readCount;
    ++lineTx;
    return e;
  }


  /**
   * Extract a line array of data from the space which contains current data.
   *
   * @param ea
     * @return
   *       Extracted line number of data.
   *
   */
  private int extract(ILine[] ea) {
    int readsize = Math.min(ea.length, readCount);
    for (int i = 0; i < readsize; ++i) {
      ea[i] = readArray[readPosition];
      readArray[readPosition] = null;
      ++readPosition;
      --readCount;
      ++lineTx;
    }
    return readsize;
  }

  /**
   * switch condition: read queue is empty && write queue is not empty.
   * Notice:This function can only be invoked after readLock is grabbed,or may
   * cause dead lock.
   *
   * @param  timeout
   *
   * @param  isInfinite
   *          whether need to wait forever until some other thread awake it.
   *         
   * @return
   *
   * @throws InterruptedException
   *
   */

  private long queueSwitch(long timeout, boolean isInfinite)
      throws InterruptedException {
    writeLock.lock();
    try {
      if (writeCount <= 0) {
        if (closed) {
          return -2;
        }
        try {
          if (isInfinite && timeout <= 0) {
            awake.await();
            return -1;
          } else {
            return awake.awaitNanos(timeout);
          }
        } catch (InterruptedException ie) {
          awake.signal();
          throw ie;
        }
      } else {
        ILine[] tmpArray = readArray;
        readArray = writeArray;
        writeArray = tmpArray;

        readCount = writeCount;
        readPosition = 0;

        writeCount = 0;
        writePosition = 0;

        notFull.signal();
        // logger.debug("Queue switch successfully!");
        return -1;
      }
    } finally {
      writeLock.unlock();
    }
  }

 
  /**
   * If exists write space, it will return true, and write one line to the space.
   * otherwise, it will try to do that in a appointed time,when time is out if still failed, return false.
   *
   * @param  line
   *       a Line.
   *
   * @param  timeout
   *       appointed limit time
   *
   * @param  unit
   *       time unit
   *
   * @return
   *       True if success,False if failed.
   *
   */
  public boolean push(ILine line, long timeout, TimeUnit unit)
      throws InterruptedException {
    if (line == null) {
      throw new NullPointerException();
    }
    long nanoTime = unit.toNanos(timeout);
    writeLock.lockInterruptibly();
    try {
      for (;;) {
        if (writeCount < writeArray.length) {
          insert(line);
          if (writeCount == 1) {
            awake.signal();
          }
          return true;
        }

        // Time out
        if (nanoTime <= 0) {
          return false;
        }
        // keep waiting
        try {
          nanoTime = notFull.awaitNanos(nanoTime);
        } catch (InterruptedException ie) {
          notFull.signal();
          throw ie;
        }
      }
    } finally {
      writeLock.unlock();
    }
  }

  /**
   * If exists write space, it will return true, and write a line array to the space.<br>
   * otherwise, it will try to do that in a appointed time,when time out if still failed, return false.
   *
   * @param  lines
   *       line array contains lines of data
   *
   * @param  size
   *       Line number needs to write to the space.
   *
   * @param  timeout
   *       appointed limit time
   *
   * @param  unit
   *       time unit
   *
   * @return
   *       status of this operation, true or false.
   *
   * @throws  InterruptedException
   *       if being interrupted during the try limit time.
   *
   */
  public boolean push(ILine[] lines, int size, long timeout, TimeUnit unit)
      throws InterruptedException {
    if (lines == null) {
      throw new NullPointerException();
    }
    long nanoTime = unit.toNanos(timeout);
    writeLock.lockInterruptibly();
    try {
      for (;;) {
        if (writeCount + size <= writeArray.length) {
          insert(lines, size);
          if (writeCount >= spillSize) {
            awake.signalAll();
          }
          return true;
        }

        // Time out
        if (nanoTime <= 0) {
          return false;
        }
        // keep waiting
        try {
          nanoTime = notFull.awaitNanos(nanoTime);
        } catch (InterruptedException ie) {
          notFull.signal();
          throw ie;
        }
      }
    } finally {
      writeLock.unlock();
    }
  }

  /**
   * Close the synchronized lock and one inner state.
   *
   */
  public void close() {
    writeLock.lock();
    try {
      closed = true;
      awake.signalAll();
    } finally {
      writeLock.unlock();
    }
  }

 
  /**
   *
   *
   * @param  timeout
   *       appointed limit time
   *
   * @param  unit
   *       time unit
   */
  public ILine pull(long timeout, TimeUnit unit) throws InterruptedException {
    long nanoTime = unit.toNanos(timeout);
    readLock.lockInterruptibly();

    try {
      for (;;) {
        if (readCount > 0) {
          return extract();
        }

        if (nanoTime <= 0) {
          return null;
        }
        nanoTime = queueSwitch(nanoTime, true);
      }
    } finally {
      readLock.unlock();
    }
  }

  /**
   *
   * @param ea    line buffer
   *
   *
   * @param  timeout
   *       a appointed limit time, must bigger than 0
   *
   * @param  unit
   *       a time unit
   *
   * @return
   *       line number of data.if less or equal than 0, means fail.
   *
   * @throws  InterruptedException
   *       if being interrupted during the try limit time.
   */
  public int pull(ILine[] ea, long timeout, TimeUnit unit)
      throws InterruptedException {
    long nanoTime = unit.toNanos(timeout);
    readLock.lockInterruptibly();

    try {
      for (;;) {
        if (readCount > 0) {
          return extract(ea);
        }

        if (nanoTime == -2) {
          return -1;
        }

        if (nanoTime <= 0) {
          return 0;
        }
        nanoTime = queueSwitch(nanoTime, false);
      }
    } finally {
      readLock.unlock();
    }
  }


  /**
   * Get size of {@link IStorage} in bytes.
   *
   * @return
   *       Storage size.
   *
   * */
  @Override
  public int size() {
    return (writeCount + readCount);
  }

//  public static void main(String []args){
//    int i = 0;
//    DoubleQueue dq = new DoubleQueue(3000,1);
//    int size = 64;
//
//    for(int k = 0; k< 10; k++){
//      PullThread thread = new PullThread(dq,size);
//      thread.start();
//    }
//    ILine[] lines = new ILine[size];
//    Date date = new Date();
//    while(i<1280000/size){
//      for(int j = 0; j< size; j++){
//        ILine line = new DefaultLine();
//        line.addField("1");
//        //line.addField("default:1000\nrange:description:the block size in which the mysql data is readmandatory:falsename:blockSize");
//        lines[j] = line;
//      }
//      try {
//        dq.push(lines, size, 3000, TimeUnit.MILLISECONDS);
//      } catch (InterruptedException e) {
//        e.printStackTrace();
//      }
//      i++;
//      System.out.println(i);
//    }
//    System.out.println(new Date().getTime()-date.getTime());
//
//  }
//  static class PullThread extends Thread{
//    DoubleQueue dq;
//    int size;
//    public PullThread(DoubleQueue dq,int size){
//      this.dq = dq;
//      this.size = size;
//    }
//    @Override
//    public void run(){
//      ILine[] lines = new ILine[size];
//      try {
//        while(true) {
//          if(dq.pull(lines,100,TimeUnit.MILLISECONDS) <= 0) {
//            break;
//          }
//        }
//      } catch (InterruptedException e) {
//        e.printStackTrace();
//      }
//    }
//  }
}

TOP

Related Classes of com.dp.nebula.wormhole.engine.storage.DoubleQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.