Package com.sissi.server.exchange.impl

Source Code of com.sissi.server.exchange.impl.FSDelegation$ByteTransferBuffer

package com.sissi.server.exchange.impl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.util.ReferenceCountUtil;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.mongodb.BasicDBObjectBuilder;
import com.sissi.commons.Trace;
import com.sissi.commons.apache.IOUtil;
import com.sissi.config.Dictionary;
import com.sissi.config.impl.MongoUtils;
import com.sissi.persistent.Persistent;
import com.sissi.pipeline.TransferBuffer;
import com.sissi.resource.ResourceCounter;
import com.sissi.server.exchange.Delegation;
import com.sissi.server.exchange.Exchanger;

/**
* 基于文件系统的离线文件代理. 索引策略:{"host":1}
*
* @author kim 2014年2月26日
*/
public class FSDelegation implements Delegation {

  private final String transfer = this.getClass().getSimpleName() + "_transfer";

  private final String chunk = this.getClass().getSimpleName() + "_chunk";

  private final Log log = LogFactory.getLog(this.getClass());

  private final File dir;

  private final int buffer;

  private final Persistent persistent;

  private final ResourceCounter resourceCounter;

  /**
   * @param dir
   * @param buffer Push缓冲区大小
   * @param resourceCounter
   * @param persistent
   */
  public FSDelegation(File dir, int buffer, ResourceCounter resourceCounter, Persistent persistent) {
    super();
    this.resourceCounter = resourceCounter;
    this.persistent = persistent;
    this.buffer = buffer;
    this.dir = this.mkdir(dir);
  }

  private File mkdir(File dir) {
    if (!dir.exists()) {
      dir.mkdirs();
    }
    return dir;
  }

  /*
   * BufferedOutputStream
   *
   * @see com.sissi.server.exchange.Delegation#allocate(java.lang.String)
   */
  @Override
  public OutputStream allocate(String sid) {
    try {
      return new BufferedOutputStream(new FileOutputStream(new File(this.dir, sid)));
    } catch (Exception e) {
      this.log.warn(e.toString());
      Trace.trace(this.log, e);
      throw new RuntimeException(e);
    }
  }

  @Override
  public Delegation push(Exchanger exchanger) {
    // {"host":Xxx}
    Map<String, Object> peek = this.persistent.peek(MongoUtils.asMap(BasicDBObjectBuilder.start(Dictionary.FIELD_HOST, exchanger.host()).get()));
    ByteTransferBuffer buffer = null;
    try {
      buffer = new ByteTransferBuffer(new BufferedInputStream(new FileInputStream(new File(FSDelegation.this.dir, peek.get(Dictionary.FIELD_SID).toString()))), Long.valueOf(peek.get(Dictionary.FIELD_SIZE).toString())).write(exchanger);
      return this;
    } catch (Exception e) {
      this.log.warn(e.toString());
      Trace.trace(this.log, e);
      throw new RuntimeException(e);
    } finally {
      IOUtil.closeQuietly(buffer);
    }
  }

  private class ByteTransferBuffer implements TransferBuffer, Closeable, Iterator<ByteTransferBuffer> {

    private final BlockingQueue<ByteBuf> queue = new LinkedBlockingQueue<ByteBuf>();

    /**
     * 已经读取字节
     */
    private final AtomicLong readable = new AtomicLong();

    /**
     * 本次读取字节
     */
    private final AtomicLong current = new AtomicLong();

    private final InputStream input;

    private final long total;

    private ByteBuf byteBuf;

    /**
     * @param input
     * @param total Si长度
     */
    public ByteTransferBuffer(InputStream input, long total) {
      super();
      this.input = input;
      this.total = total;
      FSDelegation.this.resourceCounter.increment(FSDelegation.this.transfer);
    }

    /**
     * 写入Exchanger
     *
     * @param exchanger
     * @return
     */
    public ByteTransferBuffer write(Exchanger exchanger) {
      while (this.hasNext()) {
        exchanger.write(this.next());
      }
      return this;
    }

    @Override
    public Object getBuffer() {
      return this.byteBuf;
    }

    /**
     * 流读至末尾或已读取超出Si长度
     *
     * @return
     */
    @Override
    public boolean hasNext() {
      return this.current.get() != -1 && this.readable.get() < this.total;
    }

    @Override
    public ByteTransferBuffer next() {
      try {
        ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.buffer(FSDelegation.this.buffer);
        if (this.set(byteBuf.writeBytes(this.input, byteBuf.capacity())).get() > 0) {
          this.readable.addAndGet(current.get());
        }
        this.queue.add(this.byteBuf = byteBuf);
        FSDelegation.this.resourceCounter.increment(FSDelegation.this.chunk);
        return this;
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }

    private AtomicLong set(long current) {
      this.current.set(current);
      return this.current;
    }

    @Override
    public void remove() {
    }

    @Override
    public TransferBuffer release() {
      try {
        ByteBuf byteBuf = this.queue.take();
        if (byteBuf.refCnt() > 0) {
          ReferenceCountUtil.release(byteBuf);
        }
      } catch (Exception e) {
        FSDelegation.this.log.warn(e.toString());
        Trace.trace(FSDelegation.this.log, e);
      } finally {
        this.notify();
        FSDelegation.this.resourceCounter.decrement(FSDelegation.this.chunk);
      }
      return this;
    }

    @Override
    public void close() throws IOException {
      this.current.set(-1);
      IOUtil.closeQuietly(this.input);
      FSDelegation.this.resourceCounter.decrement(FSDelegation.this.transfer);
    }
  }
}
TOP

Related Classes of com.sissi.server.exchange.impl.FSDelegation$ByteTransferBuffer

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.