|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
LogFile.java | 58.3% | 78% | 100% | 78.1% |
|
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 |
|
|
26 |
import org.activeio.Disposable;
|
|
27 |
|
|
28 |
/**
|
|
29 |
* Allows read/append access to a LogFile.
|
|
30 |
*
|
|
31 |
* @version $Revision: 1.1 $
|
|
32 |
*/
|
|
33 |
final public class LogFile implements Disposable { |
|
34 |
|
|
35 |
private final RandomAccessFile file;
|
|
36 |
private final FileChannel channel;
|
|
37 |
|
|
38 |
/** Prefered size. The size that the log file is set to when initilaized. */
|
|
39 |
private final int initialSize; |
|
40 |
|
|
41 |
/** Where the we are in the file right now */
|
|
42 |
private int currentOffset; |
|
43 |
private boolean disposed; |
|
44 |
|
|
45 | 40 |
public LogFile(File file, int initialSize) throws IOException { |
46 | 40 |
this.initialSize = initialSize;
|
47 | 40 |
boolean initializationNeeeded = !file.exists();
|
48 | 40 |
this.file = new RandomAccessFile(file, "rw"); |
49 | 40 |
channel = this.file.getChannel();
|
50 | 40 |
if( initializationNeeeded )
|
51 | 40 |
resize(); |
52 | 40 |
channel.position(0); |
53 | 40 |
reloadCurrentOffset(); |
54 |
} |
|
55 |
|
|
56 |
/**
|
|
57 |
* To avoid doing un-needed seeks.
|
|
58 |
*/
|
|
59 | 72 |
private void seek(int offset) throws IOException { |
60 | 72 |
if( offset == currentOffset ) {
|
61 | 36 |
if( currentOffset != channel.position() )
|
62 | 0 |
throw new RuntimeException(" "+currentOffset+", "+channel.position() ); |
63 | 36 |
return;
|
64 |
} |
|
65 | 36 |
channel.position(offset); |
66 | 36 |
currentOffset = offset; |
67 |
} |
|
68 | 50 |
private void reloadCurrentOffset() throws IOException { |
69 | 50 |
currentOffset= (int) channel.position();
|
70 |
} |
|
71 | 62 |
private void addToCurrentOffset(int rc) { |
72 | 62 |
currentOffset+=rc; |
73 |
} |
|
74 |
|
|
75 | 10 |
public boolean loadAndCheckRecord(int offset, Record record) throws IOException { |
76 |
|
|
77 | 10 |
try {
|
78 |
// Read the next header
|
|
79 | 10 |
seek(offset); |
80 | 10 |
record.readHeader(file); |
81 |
|
|
82 | 0 |
if (Record.isChecksumingEnabled()) {
|
83 | 0 |
record.checksum(file); |
84 |
} |
|
85 |
// Load the footer.
|
|
86 | 0 |
seek(offset+record.getPayloadLength()+Record.RECORD_HEADER_SIZE); |
87 | 0 |
record.readFooter(file); |
88 |
|
|
89 | 0 |
addToCurrentOffset(record.getRecordLength()); |
90 | 0 |
return true; |
91 |
|
|
92 |
} catch (IOException e) {
|
|
93 | 10 |
reloadCurrentOffset(); |
94 | 10 |
return false; |
95 |
} |
|
96 |
} |
|
97 |
|
|
98 | 40 |
public void resize() throws IOException { |
99 | 40 |
file.setLength(initialSize); |
100 |
} |
|
101 |
|
|
102 | 16 |
public void force() throws IOException { |
103 | 16 |
channel.force(false);
|
104 |
} |
|
105 |
|
|
106 | 40 |
public void dispose() { |
107 | 40 |
if( disposed )
|
108 | 0 |
return;
|
109 | 40 |
disposed=true;
|
110 | 40 |
try {
|
111 | 40 |
this.file.close();
|
112 |
} catch (IOException e) {
|
|
113 |
} |
|
114 |
} |
|
115 |
|
|
116 | 20 |
public void write(int offset, ByteBuffer buffer) throws IOException { |
117 |
|
|
118 | 20 |
try {
|
119 |
|
|
120 | 20 |
int size = buffer.remaining();
|
121 | 20 |
seek(offset); |
122 | 20 |
while (buffer.hasRemaining()) {
|
123 | 20 |
channel.write(buffer); |
124 |
} |
|
125 | 20 |
addToCurrentOffset(size); |
126 |
|
|
127 |
} catch (IOException e) {
|
|
128 | 0 |
reloadCurrentOffset(); |
129 |
} |
|
130 |
} |
|
131 |
|
|
132 | 30 |
public void readRecordHeader(int offset, Record record) throws IOException { |
133 | 30 |
seek(offset); |
134 | 30 |
try {
|
135 | 30 |
record.readHeader(file); |
136 |
} catch ( IOException e ) {
|
|
137 | 0 |
reloadCurrentOffset(); |
138 | 0 |
throw e;
|
139 |
} |
|
140 | 30 |
addToCurrentOffset(Record.RECORD_HEADER_SIZE); |
141 |
} |
|
142 |
|
|
143 | 12 |
public void read(int offset, byte[] answer) throws IOException { |
144 | 12 |
seek(offset); |
145 | 12 |
file.readFully(answer); |
146 | 12 |
addToCurrentOffset(answer.length); |
147 |
} |
|
148 |
} |
|