Package org.apache.derby.impl.store.raw.data

Source Code of org.apache.derby.impl.store.raw.data.ContainerOperation

/*

   Derby - Class org.apache.derby.impl.store.raw.data.ContainerOperation

   Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package org.apache.derby.impl.store.raw.data;

import org.apache.derby.iapi.services.io.FormatIdUtil;
import org.apache.derby.iapi.services.io.StoredFormatIds;
import org.apache.derby.iapi.services.sanity.SanityManager;

import org.apache.derby.iapi.store.raw.Compensation;
import org.apache.derby.iapi.store.raw.ContainerHandle;
import org.apache.derby.iapi.store.raw.LockingPolicy;
import org.apache.derby.iapi.store.raw.Transaction;
import org.apache.derby.iapi.store.raw.Undoable;

import org.apache.derby.iapi.store.raw.xact.RawTransaction;
import org.apache.derby.iapi.store.raw.data.RawContainerHandle;
import org.apache.derby.iapi.store.raw.log.LogInstant;

import org.apache.derby.iapi.error.StandardException;

import org.apache.derby.iapi.util.ByteArray;

import java.io.ObjectOutput;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.IOException;
import org.apache.derby.iapi.services.io.LimitObjectInput;

/**
  Log operation to create, drop or remove a container.

  Both the doMe or the undoMe of a create actually caused the container
  header to be modified and flushed before the log record is flushed.  This
  is necessary for 2 reasons, one is that of ensuring enough disk space, and
  the other is because unlike any other operation, the log record create
  container is in the log stream before the container is in the container
  cache.  What this mean is that if a checkpoint started after the container
  operation but before the container is kept or is dirtied in the container
  cache, then checkpoint will not know to wait for the container to be kept
  or cleaned.  The checkpoint will erroneous assume that the operation does
  not need to be redone since its log instant is before the checkpoint but in
  fact the change has not been flushed to disk.

  A drop or remove container does not have this problem.  The container exist
  and is in kept state when the operation is logged so the checkpoint will
  not overlook it and it doesn't need to flush the container header.  In the
  case of remove, the stub is flushed for a different reason - that of
  ensuring disk space.

*/
public class ContainerOperation extends ContainerBasicOperation implements Undoable
{
  protected byte operation;    // create, drop, or remove

  // in previous version of contianerOperation, there may not
  // be a createByteArray
  transient protected boolean hasCreateByteArray = true;

  protected ByteArray createByteArray;  // information necessary to
                              // recreate the container

  protected static final byte CREATE = (byte)1;
  protected static final byte DROP = (byte)2;
  protected static final byte REMOVE = (byte)4;

  protected ContainerOperation(RawContainerHandle hdl, byte operation)
     throws StandardException
  {
    super(hdl);
    this.operation = operation;
  }

  /*
   * Formatable methods
   */

  // no-arg constructor, required by Formatable
  public ContainerOperation() { super(); }

  public void writeExternal(ObjectOutput out) throws IOException 
  {
    super.writeExternal(out);
    out.writeByte(operation);

    if (operation == CREATE)
    {
      try
      {
        createByteArray = containerHdl.logCreateContainerInfo();
      }
      catch (StandardException se)
      {
        throw new IOException(se.toString());
      }
         
      createByteArray.writeExternal(out);
    }
  }

  /**
    @exception IOException cannot read log record from log stream
    @exception ClassNotFoundException cannot read ByteArray object
   */
  public void readExternal(ObjectInput in)
     throws IOException, ClassNotFoundException
  {
    super.readExternal(in);
    operation = in.readByte();

    if (operation == CREATE && hasCreateByteArray)
    {
      createByteArray = new ByteArray();
      createByteArray.readExternal(in);
    }
  }

  /**
    Return my format identifier.
  */
  public int getTypeFormatId() {
    return StoredFormatIds.LOGOP_CONTAINER;
  }


  /*
   * override ContainerBasicOperation's findContainerForLoadTran
   */
  /**
    If we are in load tran, and the operation is a create, the container
    may not (should not?) exist yet.  We need to recreate it.

    @exception StandardException Standard Cloudscape policy.
   */
  protected RawContainerHandle findContainerForLoadTran(RawTransaction xact)
     throws StandardException
  {
    if (SanityManager.DEBUG)
      SanityManager.ASSERT(createByteArray != null,
      "cannot reCreate container in load tran, createByteArray is null");

    long sid = containerId.getSegmentId();
    long cid = containerId.getContainerId();

    xact.reCreateContainerForLoadTran(sid, cid, createByteArray);

    // now we should be able to open this container
    return xact.openDroppedContainer(containerId, (LockingPolicy)null);
  }

  /**
    @exception StandardException Standard Cloudscape error policy
  */
  public final void doMe(Transaction tran, LogInstant instant,
               LimitObjectInput in)
     throws StandardException
  {

    switch (operation)
    {
    case DROP:
      containerHdl.dropContainer(instant, true);
      //
      // RESOLVE: if it hasn't been stubbified, even at redo time, we will
      // want to earmark this as a post commit work because we know it will
      // not be wasted effort.
      //
      break;

    case REMOVE:
      containerHdl.removeContainer(instant);
      break;

    case CREATE:
      break;
      // nothing to do with create container, it has already been synced to
      // disk.  If the container is subsequently dropped or even removed,
      // that's fine too.  Don't bother to find it.
    }

    releaseResource(tran);
  }


  /**
    Undo of create, drop or remove

    @param tran the transaction that is undoing this operation
    @param hdl the container handle.  This is found here during runtime
    undo - in which case we made the CLR and passed in the containerHdl
    found in generateUndo and it is passed back to this; or it is found in
    the CLR's needsRedo and is passed in and this operation never found the
    container.  Either case, release resource at the end is safe
    @param CLRInstant the log instant of the CLR
    @param in optional data
    @param dataLength optional data length

    @exception StandardException Standard Cloudscape error policy
  */
  public void undoMe(Transaction tran, RawContainerHandle hdl,
             LogInstant CLRInstant, LimitObjectInput in)
     throws StandardException
  {
    switch(operation)
    {
    case DROP:
      if (SanityManager.DEBUG) {
        SanityManager.ASSERT(hdl != null, "container handle is null");
        SanityManager.ASSERT(hdl.getContainerStatus() != RawContainerHandle.COMMITTED_DROP,
                   "Undoing a drop but the container status is not dropped");
      }
      hdl.dropContainer(CLRInstant, false); // not dropped
      break;

    case CREATE:
      // remove the container
      hdl.removeContainer(CLRInstant);
      break;

    case REMOVE:
      if (SanityManager.DEBUG) {
        SanityManager.THROWASSERT("cannot undo REMOVE, should not have generated a CLR in the first place");
      }
      break;
    }
    releaseResource(tran);

  }

  /**
    @see org.apache.derby.iapi.store.raw.Undoable
    @exception StandardException Standard Cloudscape error policy
  */
  public Compensation generateUndo(Transaction tran, LimitObjectInput in)
     throws StandardException
  {
    if (operation == REMOVE)
      return null;    // cannot undo REMOVE
    else
    {
      RawContainerHandle undoContainerHandle = findContainer(tran);
     
      // mark the container as pre-dirtied so that if a checkpoint
      // happens after the log record is sent to the log stream, the
      // cache cleaning will wait for this change.
      //
      // RESOLVE: don't do this now because if undo failed, this
      // container will be "stuck" in the preDirty state and checkpoint
      // will be stuck
      // undoContainerHandle.preDirty(true);
      //

      return new ContainerUndoOperation(undoContainerHandle, this);
    }
  }

  /** debug */
  public String toString()
  {
    if (SanityManager.DEBUG)
    {
      String str = super.toString();
      switch(operation)
      {
      case CREATE: str += " CREATE container " + containerId;
        break;
      case DROP: str += " DROP container " + containerId;
        break;
      case REMOVE: str += " REMOVE container " + containerId;
        break;
      }
      return str;
    }
    else
      return null;
  }


}
TOP

Related Classes of org.apache.derby.impl.store.raw.data.ContainerOperation

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.