📄 datafile.java
字号:
/* Sesame - Storage and Querying architecture for RDF and RDF Schema * Copyright (C) 2001-2005 Aduna * * Contact: * Aduna * Prinses Julianaplein 14 b * 3817 CS Amersfoort * The Netherlands * tel. +33 (0)33 465 99 87 * fax. +33 (0)33 465 99 87 * * http://aduna.biz/ * http://www.openrdf.org/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package org.openrdf.sesame.sailimpl.nativerdf.datastore;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.util.NoSuchElementException;/** * Class supplying access to a data file. A data file stores data sequentially. * Each entry starts with the entry's length (4 bytes), followed by the data * itself. File offsets are used to identify entries. * * @author Arjohn Kampman * @version $Revision: 1.11 $ **/public class DataFile {/*-------------+| Constants |+-------------*/ private static final long HEADER_LENGTH = 4L;/*-------------+| Variables |+-------------*/ private File _file; private RandomAccessFile _raf; private FileChannel _fileChannel; private File _txnFile; private RandomAccessFile _txnRaf; private FileChannel _txnChannel; /** Flag indicating whether the current transaction is/should be an isolated one. **/ private boolean _isolatedTransaction; private boolean _dataCleared;/*-------------+| Constructors |+-------------*/ public DataFile(File file) throws IOException { _file = file; // Make sure the file exists _file.createNewFile(); // Open a read/write channel to the file _raf = new RandomAccessFile(file, "rw"); _fileChannel = _raf.getChannel(); if (_fileChannel.size() == 0L) { // Empty file, insert 4 dummy bytes at the start of the file _fileChannel.write( ByteBuffer.wrap(new byte[] {0, 0, 0, 0}) ); } }/*----------+| Methods |+----------*/ public void startTransaction(boolean isolateTransaction) throws IOException { _isolatedTransaction = isolateTransaction; if (isolateTransaction) { // Make sure the transaction file exists and that it is empty _txnFile = new File(_file.getParentFile(), "txn_" + _file.getName()); _txnFile.createNewFile(); _txnRaf = new RandomAccessFile(_txnFile, "rw"); _txnChannel = _txnRaf.getChannel(); _txnChannel.truncate(0L); _dataCleared = false; } } public void commitTransaction() throws IOException { if (_isolatedTransaction) { if (_dataCleared) { // Discard existing data _fileChannel.truncate(HEADER_LENGTH); } // Append the txn file to the data file _txnChannel.position(0L); TransferUtil.transferFrom(_txnChannel, _fileChannel.size(), _txnChannel.size(), _fileChannel); _txnRaf.close(); _txnRaf = null; _txnChannel = null; // Delete the txn file _txnFile.delete(); _txnFile = null; } } public void rollbackTransaction() throws IOException { if (_isolatedTransaction) { // Close and discard the txn channel _txnRaf.close(); _txnRaf = null; _txnChannel = null; // Delete the txn file _txnFile.delete(); _txnFile = null; } else { throw new IOException("Unisolated transactions cannot be rolled back"); } } /** * Stores the specified data and returns the byte-offset at which it has * been stored. **/ public long storeData(byte[] data) throws IOException { if (_isolatedTransaction) { // Append the data to the txn file long offset = _txnChannel.size(); _writeData(_txnChannel, offset, data); // Txn file will be appended to data file on commit, // add size of data file to the offset if (_dataCleared) { // data file will be truncated to 4 bytes on commit return HEADER_LENGTH + offset; } else { return _fileChannel.size() + offset; } } else { long offset = _fileChannel.size(); _writeData(_fileChannel, offset, data); return offset; } } /** * Updates (replaces) the data at the specified offset with the supplied data. **/ public void updateData(long offset, byte[] data) throws IOException { FileChannel channel = _fileChannel; if (_isolatedTransaction && (_dataCleared || offset >= _fileChannel.size())) { // Write the data to the txn file channel = _txnChannel; offset -= _dataCleared ? HEADER_LENGTH : _fileChannel.size(); } _writeData(channel, offset, data); } private void _writeData(FileChannel channel, long offset, byte[] data) throws IOException { ByteBuffer buf = ByteBuffer.allocate(data.length + 4); buf.putInt(data.length); buf.put(data); buf.rewind(); channel.write(buf, offset); } /** * Gets the data that is stored at the specified offset. * * @param offset An offset in the data file. * @param dirtyReads Flag indicating whether data that hasn't been committed * yet should be searched too. * @return The data that was found on the specified offset. * @exception IOException If an I/O error occurred. **/ public byte[] getData(long offset, boolean dirtyReads) throws IOException { FileChannel channel = _fileChannel; if (dirtyReads && _isolatedTransaction && (_dataCleared || offset >= _fileChannel.size())) { // Check txn file channel = _txnChannel; offset -= _dataCleared ? HEADER_LENGTH : _fileChannel.size(); } // FIXME: maybe get more data in one go is more efficient? ByteBuffer buf = ByteBuffer.allocate(4); channel.read(buf, offset); int dataLength = buf.getInt(0); byte[] data = new byte[dataLength]; buf = ByteBuffer.wrap(data); channel.read(buf, offset + 4L); return data; } public void clear() throws IOException { if (_isolatedTransaction) { _txnChannel.truncate(0L); // Existing data is deleted on commit _dataCleared = true; } else { _fileChannel.truncate(HEADER_LENGTH); } } public void close() throws IOException { if (_txnChannel != null) { rollbackTransaction(); } _raf.close(); } public DataIterator iterator() { return new DataIterator(); } public class DataIterator { private long _position = HEADER_LENGTH; public boolean hasNext() throws IOException { return _position < _fileChannel.size(); } public byte[] next() throws IOException { if (!hasNext()) { throw new NoSuchElementException(); } byte[] data = getData(_position, false); _position += (4 + data.length); return data; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -