Package com.sun.messaging.jmq.jmsserver.persist.file

Source Code of com.sun.messaging.jmq.jmsserver.persist.file.TransactionWorkInfo

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* @(#)MessageInfo.java  1.22 08/31/07
*/

package com.sun.messaging.jmq.jmsserver.persist.file;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;

import com.sun.messaging.jmq.io.VRFile;
import com.sun.messaging.jmq.io.VRFileRAF;
import com.sun.messaging.jmq.io.VRecordRAF;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.data.TransactionUID;
import com.sun.messaging.jmq.jmsserver.data.BaseTransaction;
import com.sun.messaging.jmq.jmsserver.data.TransactionWorkFactory;
import com.sun.messaging.jmq.jmsserver.persist.Store;
import com.sun.messaging.jmq.jmsserver.resources.BrokerResources;
import com.sun.messaging.jmq.jmsserver.util.BrokerException;
import com.sun.messaging.jmq.util.log.Logger;

/**
* MessageInfo keeps track of a message and it's ack list. Has methods to parse
* and persist them.
*/
class TransactionWorkInfo {
  static final short PENDING = -1; // -1=0xffff
  static final short DONE = 0;
  private static final int BYTE_SIZE = 1;
  private static final int SHORT_SIZE = 2;
  private static final int INT_SIZE = 4;
  private static final int LONG_SIZE = 8;

  // each entry for an interest (identified by ConsumerUID) and it's state
  // has: a long (ConsumerUID) and an int (state)
  private static final int ENTRY_SIZE = LONG_SIZE + INT_SIZE;

  private Logger logger = Globals.getLogger();
  private BrokerResources br = Globals.getBrokerResources();

  private BaseTransaction msg; // will set to null after client has it
  // bytes

  // cached info
  private TransactionUID tid;
  private int txnDataSize;

  private PreparedTxnStore parent = null;

  // backing buffer
  private VRecordRAF vrecord = null;

  /**
   * if this returns successfully, the message and it's interest list are
   * loaded from backing file message is from an individual file
   */
  TransactionWorkInfo(PreparedTxnStore p, byte[] data, byte[] ilist)
      throws IOException {

    parent = p;

    try {
      // parse message
      BaseTransaction txnWork = TransactionWorkFactory
          .readFromBytes(data);

      // cache message info
      this.msg = txnWork;
      tid = (TransactionUID) txnWork.getTid();

    } catch (BrokerException be) {
      be.printStackTrace();
      throw new IOException(be.getMessage());
    } catch (IOException e) {
      logger.log(logger.ERROR, parent.storeName
          + ":failed to parse message from byte array", e);
      throw e;
    }
  }

  /**
   * if this returns successfully, the message and it's interest list are
   * loaded from backing file message is from vrfile
   */
  TransactionWorkInfo(PreparedTxnStore p, VRecordRAF r) throws IOException {
    parent = p;
    vrecord = r;

    // sanity check done while VRecords are loaded

    try {
      // parse message
      BaseTransaction txnWork = parseTransactionWork(r);

      // cache message info
      this.msg = txnWork;
      tid = txnWork.getTid();

    } catch (IOException e) {
      // free the bad VRecord
      parent.getVRFile().free(vrecord);

      throw e;
    }
  }

  /**
   * if this returns successfully, message and it's interest states are
   * persisted store message in vrfile
   */
  TransactionWorkInfo(PreparedTxnStore p, VRFileRAF vrfile,
      BaseTransaction txnWork, byte[] databuf, boolean sync) throws IOException {

    parent = p;

    // cache message info
    tid = txnWork.getTid();
    txnDataSize = databuf.length;

    // format of data in buffer:
    // size of message (packetSize, int)
    // message (a blob)
    // size of interest list (int)
    // each interest entry has:
    // long
    // int

    int bufsize = INT_SIZE + txnDataSize + INT_SIZE;
    if(sync && Store.getDEBUG_SYNC())
    {
      String msg = "TransactionWorkInfor sync() "+tid;
      logger.log(Logger.DEBUG,msg);
    }

    if (!Globals.isMinimizeWrites()) {
      synchronized (vrfile) {
        vrecord = (VRecordRAF) vrfile.allocate(bufsize);

        // start writing
        vrecord.setCookie(PENDING);

        // write packetSize
        vrecord.writeInt(txnDataSize);

        // write message
       
        vrecord.write(databuf);
       

        // done writing
        vrecord.setCookie(DONE);

        if (sync) {
          vrecord.force();
        }
      }
    } else {
      synchronized (vrfile) {
        // byte[] recordData = new byte[]
        // we will write the state and cooky at the same time as data
        // so need another 4 bytes (2 * short);
        ByteBuffer bbuf = ByteBuffer.allocate(bufsize + 4);

        bbuf.putShort(VRFile.STATE_ALLOCATED);
        bbuf.putShort(DONE);
        bbuf.putInt(txnDataSize);

        // write message
       
        bbuf.put(databuf);
       
        byte[] data = bbuf.array();

        vrecord = (VRecordRAF) vrfile.allocateAndWrite(bufsize, data);

        if (sync) {
          vrecord.force();
        }
      }
    }
  }

  /**
   * if this returns successfully, message and it's interest states are
   * persisted; store message in individual files
   */
  TransactionWorkInfo(PreparedTxnStore p, BaseTransaction txnWork,byte[] databuf,
      boolean sync) throws IOException {
//    System.out.println("store in individual file");

    this.parent = p;

    tid = txnWork.getTid();
    if(databuf!=null)
      txnDataSize = databuf.length;
   
   
    parent.writeData(tid, databuf, null, sync);

  }

  /**
   * Return the message. The message is only cached when it is loaded from the
   * backing buffer the first time. It will be set to null after it is
   * retrieved. From then on, we always read it from the backing buffer again.
   */
  synchronized BaseTransaction getMessage() throws IOException {
    if (msg == null) {
      if (vrecord != null) {
        // read from backing buffer
        try {
          return parseTransactionWork(vrecord);
        } catch (IOException e) {
          logger.log(logger.ERROR, parent.storeName
              + ":failed to parse message from vrecord("
              + vrecord + ")", e);
          throw e;
        }
      } else {
        try {
          byte data[] = parent.loadData(tid);
          return parseTransactionWork(data);
        } catch (IOException e) {
          logger.log(logger.ERROR, parent.storeName
              + ":failed to parse message from byte array", e);
          throw e;
        }
      }
    } else {
      BaseTransaction pkt = msg;
      msg = null;
      return pkt;
    }
  }

 

  // no need to synchronized, value set at object creation and wont change
  int getSize() {
    return txnDataSize;
  }

  // no need to synchronized, value set at object creation and wont change
  TransactionUID getID() {
    return tid;
  }

  /**
   * clear out all cached info and release the backing buffer
   */
  synchronized void free(boolean sync) throws IOException {
    if(sync && Store.getDEBUG_SYNC())
    {
      String msg = "TransactionWorkInfo free sync() "+ getID();
      logger.log(Logger.DEBUG,msg);
    }
    if (vrecord != null) {
      parent.getVRFile().free(vrecord);
      if (sync) {
        parent.getVRFile().force();
      }
      vrecord = null;
    } else {
      parent.removeData(tid, sync);
    }

    tid = null;

  }

  private BaseTransaction parseTransactionWork(byte[] data)
      throws IOException {
    try {
      BaseTransaction txnWork = TransactionWorkFactory
          .readFromBytes(data);

      return txnWork;
    } catch (Throwable t) {
      logger.log(logger.ERROR, parent.storeName
          + ":failed to parse message(size=" + txnDataSize + ") ", t);
      IOException e = new IOException(t.toString());
      e.setStackTrace(t.getStackTrace());
      throw e;
    }
  }

  private BaseTransaction parseTransactionWork(VRecordRAF r)
      throws IOException {

    try {
      r.rewind();

      txnDataSize = r.readInt();

      byte[] data = new byte[txnDataSize];
      r.read(data);
      BaseTransaction txnWork = TransactionWorkFactory
          .readFromBytes(data);

      return txnWork;
    } catch (Throwable t) {
      logger.log(logger.ERROR, parent.storeName
          + ":failed to parse message(size=" + txnDataSize
          + ") from vrecord(" + r + ")", t);
      IOException e = new IOException(t.toString());
      e.setStackTrace(t.getStackTrace());
      throw e;
    }
  }

  synchronized void updateState(int state, boolean sync) throws IOException,
      BrokerException {

    // long   (txnId)
    long valOffset = LONG_SIZE + BYTE_SIZE;
    writeIntAtOffset(valOffset, state, sync);

  }

  synchronized void updateCompletion(int completionVal, boolean sync)
      throws IOException, BrokerException {

    // long   (txnId)
    long valOffset = LONG_SIZE + BYTE_SIZE + INT_SIZE;
    writeIntAtOffset(valOffset, completionVal, sync);

  }

  void writeIntAtOffset(long valOffset, int val, boolean sync)
      throws IOException, BrokerException {
   
    if(sync && Store.getDEBUG_SYNC())
    {
      String msg = "TransactionWorkInfo sync() "+tid;
      logger.log(Logger.DEBUG,msg);
    }
   
    if (vrecord != null) {

      // offset into VRecord
      // state gets written immediately after the transactionid

      //short: allocated state
      //short: complete state
      //int:   data size
      //+ type offset (see above)   
      //Globals.getLogger().log(Logger.INFO, " vv writeIntAtOffset = " + val);
     
    //  long offset = SHORT_SIZE + SHORT_SIZE + INT_SIZE + valOffset;
      long offset = SHORT_SIZE + SHORT_SIZE  + valOffset;
      vrecord.writeInt((int) offset, val);
      if (sync) {
        vrecord.force();
      }
    } else {
      // offset into attachment part     

      if (!parent.writeAttachmentData(tid, valOffset, true, val, sync)) {
        logger.log(logger.ERROR, br.E_MSG_NOT_FOUND_IN_STORE, tid,
            parent.storeName);
        throw new BrokerException(br.getString(
            br.E_MSG_NOT_FOUND_IN_STORE, tid, parent.storeName));
      }

    }
  }

}
TOP

Related Classes of com.sun.messaging.jmq.jmsserver.persist.file.TransactionWorkInfo

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.