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 }