001: package com.jofti.store;
002:
003: import java.io.File;
004: import java.io.FileNotFoundException;
005: import java.io.IOException;
006: import java.io.RandomAccessFile;
007: import java.nio.channels.FileChannel;
008: import java.nio.channels.FileLock;
009:
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012:
013: import com.jofti.exception.JoftiException;
014:
015: class FileStore {
016: File file = null;
017:
018: /**
019: * @see java.io.RandomAccessFile#RandomAccessFile(java.lang.String, java.lang.String)
020: */
021: String fileMode = "rw";
022:
023: /**
024: * FileChannel associated with this FileStore.
025: *
026: * <p>The FileChannel is private to guarantee that all calls to the
027: * channel methods come through this FileStore.
028: */
029: FileChannel channel = null;
030:
031: protected int fileId = 0;
032:
033: private static Log log = LogFactory.getLog(FileManager.class);
034:
035: /**
036: * FileChannel.position() of last read or write.
037: *
038: * <p>May be used to report the file position when IOException occurs.
039: */
040: long nextPosition = 0;
041:
042: /**
043: * indicates the file was created during the call to open()
044: * @see #open(String filemode)
045: */
046: boolean newFile = true;
047:
048: /**
049: * FileLock acquired when file is opened.
050: */
051:
052: FileLock lock = null;
053:
054: Object recordLock = new Object();
055:
056: long writes = 0;
057:
058: /**
059: * construct an instance of FileStore for a given file name
060: * @param file filename
061: */
062: FileStore(File file, int id) {
063: this .file = file;
064: this .fileId = id;
065: }
066:
067: /**
068: * open the file and get the associated nio FileChannel for the file.
069: *
070: * <p>
071: * If the file does not exist, then the newFile member is set true.
072: *
073: * @param fileMode
074: * value passed to RandomAccessFile constructor.
075: * @throws FileNotFoundException
076: * if the parent directory structure does not exist.
077: * @see java.io.RandomAccessFile#RandomAccessFile(java.lang.String,
078: * java.lang.String)
079: */
080: FileStore open(String fileMode) throws JoftiException,
081: FileNotFoundException {
082: this .fileMode = fileMode;
083:
084: // remember whether the file existed or not
085: newFile = !file.exists();
086:
087: // if it already existed, but length is zero, then it is still a new file
088: if (!newFile)
089: newFile = file.length() == 0;
090:
091: channel = new RandomAccessFile(file, fileMode).getChannel();
092:
093: try {
094: lock = channel.tryLock();
095: } catch (IOException e) {
096: throw new JoftiException(e);
097: }
098: if (lock == null)
099: log.info("Unable to obtain lock on "
100: + file.getAbsolutePath());
101:
102: return this ;
103: }
104:
105: /**
106: * Close the channel associated with this FileStore.
107: * <p>Also releases the lock that is held on the file.
108: * @return this FileStore
109: * @throws IOException
110: */
111: FileStore close() throws IOException {
112: if (channel.isOpen()) {
113: if (lock != null) {
114: lock.release();
115: }
116: channel.close();
117: }
118: return this ;
119: }
120:
121: /**
122: * Helper provides access to the FileChannel.write() method for
123: * the FileChannel associated with this FileStore.
124: * @param lb Reference to a LogBuffer object that is to be written.
125: * @throws IOException
126: */
127: void write(BlockBuffer lb) throws IOException {
128:
129: channel.write(lb.buffer, lb.positionHolder.position);
130:
131: // force
132: if (writes % 10000 == 0) {
133: force(true);
134: }
135: writes++;
136: }
137:
138: /**
139: *
140: * @param forceMetadata as defined by FileChannel.force()
141: * @throws IOException
142: * @see FileChannel#force(boolean)
143: */
144: void force(boolean forceMetadata) throws IOException {
145: channel.force(forceMetadata);
146: }
147:
148: }
|