Example #1
0
  /**
   * Obtain next block of data from source
   *
   * @throws MessagingException
   */
  public void exportAction(RawProcessor.ExportInternalMessage m) throws MessagingException {
    assert (m.m_m.getGeneration() == m_generation);
    ExportProtoMessage message = m.m_m;
    ExportProtoMessage result =
        new ExportProtoMessage(message.getGeneration(), message.m_partitionId, message.m_signature);
    ExportInternalMessage mbp = new ExportInternalMessage(m.m_sb, result);
    StreamBlock first_unpolled_block = null;

    // Assemble a list of blocks to delete so that they can be deleted
    // outside of the m_committedBuffers critical section
    ArrayList<StreamBlock> blocksToDelete = new ArrayList<StreamBlock>();

    boolean hitEndOfStreamWithNoRunnable = false;
    try {
      // Perform all interaction with m_committedBuffers under lock
      // because pushExportBuffer may be called from an ExecutionSite at any time
      synchronized (m_committedBuffers) {
        // Process the ack if any and add blocks to the delete list or move the released USO pointer
        if (message.isAck() && message.getAckOffset() > 0) {
          try {
            releaseExportBytes(message.getAckOffset(), blocksToDelete);
          } catch (IOException e) {
            VoltDB.crashLocalVoltDB("Error attempting to release export bytes", true, e);
            return;
          }
        }

        if (m_endOfStream && m_committedBuffers.sizeInBytes() == 0) {
          if (m_onDrain != null) {
            try {
              m_onDrain.run();
            } finally {
              m_onDrain = null;
            }
          } else {
            hitEndOfStreamWithNoRunnable = true;
          }
          return;
        }

        // Reset the first unpolled uso so that blocks that have already been polled will
        // be served up to the next connection
        if (message.isClose()) {
          try {
            resetPollMarker();
          } catch (IOException e) {
            exportLog.error(e);
          }
        }

        // Inside this critical section do the work to find out
        // what block should be returned by the next poll.
        // Copying and sending the data will take place outside the critical section
        try {
          if (message.isPoll()) {
            Iterator<StreamBlock> iter = m_committedBuffers.iterator();
            while (iter.hasNext()) {
              StreamBlock block = iter.next();
              // find the first block that has unpolled data
              if (m_firstUnpolledUso < block.uso() + block.totalUso()) {
                first_unpolled_block = block;
                m_firstUnpolledUso = block.uso() + block.totalUso();
                break;
              } else {
                blocksToDelete.add(block);
                iter.remove();
              }
            }
          }
        } catch (RuntimeException e) {
          if (e.getCause() instanceof IOException) {
            VoltDB.crashLocalVoltDB("Error attempting to find unpolled export data", true, e);
          } else {
            throw e;
          }
        }
      }
    } finally {
      // Try hard not to leak memory
      for (StreamBlock sb : blocksToDelete) {
        sb.deleteContent();
      }
      // Cheesy hack for now where we serve info about old
      // data sources from previous generations. In reality accessing
      // this generation is something of an error
      if (hitEndOfStreamWithNoRunnable) {
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.putInt(0).flip();
        result.pollResponse(m_firstUnpolledUso, buf);
        mbp.m_sb.event(result);
      }
    }

    if (message.isPoll()) {
      // If there are no unpolled blocks return the firstUnpolledUSO with no data
      if (first_unpolled_block == null) {
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.putInt(0).flip();
        result.pollResponse(m_firstUnpolledUso, buf);
      } else {
        // Otherwise return the block with the USO for the end of the block
        // since the entire remainder of the block is being sent.
        result.pollResponse(
            first_unpolled_block.uso() + first_unpolled_block.totalUso(),
            first_unpolled_block.unreleasedBuffer());
      }
      mbp.m_sb.event(result);
    }
  }