View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Hiram Chirino
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   **/
    18  package org.activeio.journal.active;
    19
    20  import java.io.File;
    21  import java.io.IOException;
    22  import java.io.RandomAccessFile;
    23  import java.nio.ByteBuffer;
    24  import java.nio.channels.FileChannel;
    25  import java.nio.channels.FileLock;
    26
    27  import org.activeio.Disposable;
    28  import org.activeio.Packet;
    29  import org.activeio.packet.ByteBufferPacket;
    30
    31  /***
    32   * Control file holds the last known good state of the journal.  It stores the state in
    33   * record that is versioned and repeated twice in the file so that a failure in the
    34   * middle of the write of the first or second record do not not result in an unknown
    35   * state.
    36   *
    37   * @version $Revision: 1.1 $
    38   */
    39  final public class ControlFile implements Disposable {
    40
    41      /*** The File that holds the control data. */
    42      private final RandomAccessFile file;
    43      private final FileChannel channel;
    44      private final ByteBufferPacket controlData;
    45
    46      private long controlDataVersion=0;
    47      private FileLock lock;
    48  	private boolean disposed;
    49
    50      public ControlFile(File fileName, int controlDataSize) throws IOException {
    51
    52          boolean existed = fileName.exists();
    53          file = new RandomAccessFile(fileName, "rw");
    54          channel = file.getChannel();
    55          controlData = new ByteBufferPacket(ByteBuffer.allocateDirect(controlDataSize));
    56
    57      }
    58
    59      /***
    60       * Locks the control file.
    61       * @throws IOException
    62       */
    63      public void lock() throws IOException {
    64          if( lock==null ) {
    65              lock = channel.tryLock();
    66              if( lock ==null )
    67                  throw new IOException("Journal is allready opened by another application");
    68          }
    69      }
    70
    71      /***
    72       * Un locks the control file.
    73       * @throws IOException
    74       */
    75      public void unlock() throws IOException {
    76          if( lock != null ) {
    77              lock.release();
    78              lock=null;
    79          }
    80      }
    81
    82      public boolean load() throws IOException {
    83          long l = file.length();
    84          if( l < controlData.capacity() ) {
    85              controlDataVersion=0;
    86              controlData.position(0);
    87              controlData.limit(0);
    88              return false;
    89          } else {
    90              file.seek(0);
    91              long v1 = file.readLong();
    92              file.seek(controlData.capacity()+8);
    93              long v1check = file.readLong();
    94
    95              file.seek(controlData.capacity()+16);
    96              long v2 = file.readLong();
    97              file.seek((controlData.capacity()*2)+24);
    98              long v2check = file.readLong();
    99
    100             if( v2 == v2check ) {
    101                 controlDataVersion = v2;
    102                 file.seek(controlData.capacity()+24);
    103                 controlData.clear();
    104                 channel.read(controlData.getByteBuffer());
    105             } else if ( v1 == v1check ){
    106                 controlDataVersion = v1;
    107                 file.seek(controlData.capacity()+8);
    108                 controlData.clear();
    109                 channel.read(controlData.getByteBuffer());
    110             } else {
    111                 // Bummer.. Both checks are screwed. we don't know
    112                 // if any of the two buffer are ok.  This should
    113                 // only happen is data got corrupted.
    114                 throw new IOException("Control data corrupted.");
    115             }
    116             return true;
    117         }
    118     }
    119
    120     public void store() throws IOException {
    121         controlDataVersion++;
    122         file.setLength((controlData.capacity()*2)+32);
    123         file.seek(0);
    124
    125         // Write the first copy of the control data.
    126         file.writeLong(controlDataVersion);
    127         controlData.clear();
    128         channel.write(controlData.getByteBuffer());
    129         file.writeLong(controlDataVersion);
    130
    131         // Write the second copy of the control data.
    132         file.writeLong(controlDataVersion);
    133         controlData.clear();
    134         channel.write(controlData.getByteBuffer());
    135         file.writeLong(controlDataVersion);
    136
    137         channel.force(false);
    138     }
    139
    140     public Packet getControlData() {
    141         controlData.clear();
    142         return controlData;
    143     }
    144
    145     public void dispose() {
    146     	if( disposed )
    147     		return;
    148     	disposed=true;
    149         try {
    150             unlock();
    151         } catch (IOException e) {
    152         }
    153         try {
    154             file.close();
    155         } catch (IOException e) {
    156         }
    157     }
    158 }