@Override
 @SuppressWarnings("unchecked")
 public synchronized void write(ArchivePacket packet) throws IOException {
   if (!isOpen()) {
     throw new IOException("not open");
   }
   if (out == null) {
     throw new IOException("no output stream found");
   }
   if (packet == null || packet.payload() == null) {
     throw new IOException("no payload to write for entry");
   }
   byte[] buf = packet.payload().toString().getBytes();
   String name = ArchiveUtils.encodeArchiveEntryName(packet);
   ArchiveEntry entry = out.newArchiveEntry();
   entry.setName(name);
   entry.setLastModified(new Date());
   entry.setEntrySize(buf.length);
   out.putArchiveEntry(entry);
   out.write(buf);
   out.closeArchiveEntry();
   packetCounter++;
   if (watcher.getBytesToTransfer() != 0
       && watcher.getBytesTransferred() > watcher.getBytesToTransfer()) {
     logger.debug(
         "bytes watcher: transferred = {}, rate {}",
         watcher.getBytesTransferred(),
         watcher.getRecentByteRatePerSecond());
     switchToNextArchive();
     watcher.resetWatcher();
   }
 }
Beispiel #2
0
  /**
   * Initiate a low-copy transfer between two stream channels. The pool should be a direct buffer
   * pool for best performance.
   *
   * @param source the source channel
   * @param sink the target channel
   * @param sourceListener the source listener to set and call when the transfer is complete, or
   *     {@code null} to clear the listener at that time
   * @param sinkListener the target listener to set and call when the transfer is complete, or
   *     {@code null} to clear the listener at that time
   * @param readExceptionHandler the read exception handler to call if an error occurs during a read
   *     operation
   * @param writeExceptionHandler the write exception handler to call if an error occurs during a
   *     write operation
   * @param pool the pool from which the transfer buffer should be allocated
   */
  public static <I extends StreamSourceChannel, O extends StreamSinkChannel> void initiateTransfer(
      final I source,
      final O sink,
      final ChannelListener<? super I> sourceListener,
      final ChannelListener<? super O> sinkListener,
      final ChannelExceptionHandler<? super I> readExceptionHandler,
      final ChannelExceptionHandler<? super O> writeExceptionHandler,
      Pool<ByteBuffer> pool) {
    if (pool == null) {
      throw UndertowMessages.MESSAGES.argumentCannotBeNull("pool");
    }
    final Pooled<ByteBuffer> allocated = pool.allocate();
    boolean free = true;
    try {
      final ByteBuffer buffer = allocated.getResource();
      long read;
      for (; ; ) {
        try {
          read = source.read(buffer);
          buffer.flip();
        } catch (IOException e) {
          ChannelListeners.invokeChannelExceptionHandler(source, readExceptionHandler, e);
          return;
        }
        if (read == 0 && !buffer.hasRemaining()) {
          break;
        }
        if (read == -1 && !buffer.hasRemaining()) {
          done(source, sink, sourceListener, sinkListener);
          return;
        }
        while (buffer.hasRemaining()) {
          final int res;
          try {
            res = sink.write(buffer);
          } catch (IOException e) {
            ChannelListeners.invokeChannelExceptionHandler(sink, writeExceptionHandler, e);
            return;
          }
          if (res == 0) {
            break;
          }
        }
        if (buffer.hasRemaining()) {
          break;
        }
        buffer.clear();
      }
      Pooled<ByteBuffer> current = null;
      if (buffer.hasRemaining()) {
        current = allocated;
        free = false;
      }

      final TransferListener<I, O> listener =
          new TransferListener<I, O>(
              pool,
              current,
              source,
              sink,
              sourceListener,
              sinkListener,
              writeExceptionHandler,
              readExceptionHandler,
              read == -1);
      sink.getWriteSetter().set(listener);
      source.getReadSetter().set(listener);
      // we resume both reads and writes, as we want to keep trying to fill the buffer
      if (current == null || buffer.capacity() != buffer.remaining()) {
        // we don't resume if the buffer is 100% full
        source.resumeReads();
      }
      if (current != null) {
        // we don't resume writes if we have nothing to write
        sink.resumeWrites();
      }
    } finally {
      if (free) {
        allocated.free();
      }
    }
  }
Beispiel #3
0
    public void handleEvent(final Channel channel) {
      if (done) {
        if (channel instanceof StreamSinkChannel) {
          ((StreamSinkChannel) channel).suspendWrites();
        } else if (channel instanceof StreamSourceChannel) {
          ((StreamSourceChannel) channel).suspendReads();
        }
        return;
      }
      boolean noWrite = false;
      if (pooledBuffer == null) {
        pooledBuffer = pool.allocate();
        noWrite = true;
      } else if (channel instanceof StreamSourceChannel) {
        noWrite = true; // attempt a read first, as this is a read notification
        pooledBuffer.getResource().compact();
      }

      final ByteBuffer buffer = pooledBuffer.getResource();
      try {
        long read;

        for (; ; ) {
          boolean writeFailed = false;
          // always attempt to write first if we have the buffer
          if (!noWrite) {
            while (buffer.hasRemaining()) {
              final int res;
              try {
                res = sink.write(buffer);
              } catch (IOException e) {
                pooledBuffer.free();
                pooledBuffer = null;
                done = true;
                ChannelListeners.invokeChannelExceptionHandler(sink, writeExceptionHandler, e);
                return;
              }
              if (res == 0) {
                writeFailed = true;
                break;
              }
            }
            if (sourceDone && !buffer.hasRemaining()) {
              done = true;
              done(source, sink, sourceListener, sinkListener);
              return;
            }
            buffer.compact();
          }
          noWrite = false;

          if (buffer.hasRemaining() && !sourceDone) {
            try {
              read = source.read(buffer);
              buffer.flip();
            } catch (IOException e) {
              pooledBuffer.free();
              pooledBuffer = null;
              done = true;
              ChannelListeners.invokeChannelExceptionHandler(source, readExceptionHandler, e);
              return;
            }
            if (read == 0) {
              break;
            } else if (read == -1) {
              sourceDone = true;
              if (!buffer.hasRemaining()) {
                done = true;
                done(source, sink, sourceListener, sinkListener);
                return;
              }
            }
          } else {
            buffer.flip();
            if (writeFailed) {
              break;
            }
          }
        }
        // suspend writes if there is nothing to write
        if (!buffer.hasRemaining()) {
          sink.suspendWrites();
        } else if (!sink.isWriteResumed()) {
          sink.resumeWrites();
        }
        // suspend reads if there is nothing to read
        if (buffer.remaining() == buffer.capacity()) {
          source.suspendReads();
        } else if (!source.isReadResumed()) {
          source.resumeReads();
        }
      } finally {
        if (pooledBuffer != null && !buffer.hasRemaining()) {
          pooledBuffer.free();
          pooledBuffer = null;
        }
      }
    }