package org.opendedup.collections; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; //import java.nio.file.Path; //import java.nio.file.Paths; import java.util.Arrays; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; public class LargeLongByteArrayMap implements AbstractMap { private long fileSize = 0; private int arraySize = 0; // RandomAccessFile bdbf = null; String fileName; boolean closed = true; private ReentrantLock hashlock = new ReentrantLock(); private static Logger log = Logger.getLogger("sdfs"); public LargeLongByteArrayMap(String fileName, long initialSize, int arraySize) throws IOException { if (initialSize > 0) this.fileSize = initialSize; this.arraySize = arraySize; this.fileName = fileName; this.openFile(); this.closed = false; } private void openFile() throws IOException { File f = new File(this.fileName); if (!f.exists()) f.getParentFile().mkdirs(); RandomAccessFile bdbf = null; try { bdbf = new RandomAccessFile(fileName, "rw"); if (this.fileSize > 0) bdbf.setLength(this.fileSize); } catch (Exception e) { throw new IOException(e); } finally { bdbf.close(); bdbf = null; } } public void setLength(long length) throws IOException { RandomAccessFile bdbf = null; try { bdbf = new RandomAccessFile(fileName, "rw"); bdbf.setLength(length); } catch (Exception e) { throw new IOException(e); } finally { bdbf.close(); bdbf = null; } } public void lockCollection() { this.hashlock.lock(); } public void unlockCollection() { this.hashlock.unlock(); } @Override public void close() { this.hashlock.lock(); this.hashlock.unlock(); this.closed = true; RandomAccessFile bdbf = null; try { bdbf = new RandomAccessFile(fileName, "rw"); bdbf.getFD().sync(); } catch (Exception e) { } finally { try { bdbf.close(); } catch (IOException e) { } } System.gc(); } @Override public byte[] get(long pos) throws IOException { return this.get(pos, true); } public byte[] get(long pos, boolean checkForLock) throws IOException { if (checkForLock) { this.hashlock.lock(); this.hashlock.unlock(); } byte[] b = new byte[this.arraySize]; RandomAccessFile rf = null; try { rf = new RandomAccessFile(this.fileName, "rw"); rf.seek(pos); rf.read(b); } catch (Exception e) { throw new IOException(e); } finally { rf.close(); rf = null; } return b; } public boolean isClosed() { return this.closed; } public void put(long pos, byte[] data) throws IOException { this.hashlock.lock(); this.hashlock.unlock(); if (data.length != this.arraySize) throw new IOException(" size mismatch " + data.length + " does not equal " + this.arraySize); RandomAccessFile rf = null; try { rf = new RandomAccessFile(this.fileName, "rw"); rf.seek(pos); rf.write(data); } catch (Exception e) { throw new IOException(e); } finally { rf.close(); rf = null; } } public void remove(long pos) throws IOException { this.remove(pos, true); } public void remove(long pos, boolean checkForLock) throws IOException { if (checkForLock) { this.hashlock.lock(); this.hashlock.unlock(); } RandomAccessFile rf = null; try { rf = new RandomAccessFile(this.fileName, "rw"); rf.seek(pos); rf.write(new byte[this.arraySize]); } catch (Exception e) { throw new IOException(e); } finally { rf.close(); rf = null; } } @Override public void sync() throws IOException { RandomAccessFile bdbf = new RandomAccessFile(fileName, "rw"); bdbf.getFD().sync(); bdbf.close(); bdbf = null; } @Override public void vanish() throws IOException { RandomAccessFile bdbf = null; try { bdbf = new RandomAccessFile(fileName, "rw"); bdbf.setLength(0); } catch (Exception e) { throw new IOException(e); } finally { bdbf.close(); bdbf = null; } } public void copy(String destFilePath) throws IOException { this.hashlock.lock(); try { this.sync(); File f = new File(destFilePath); if (f.exists()) f.delete(); else f.getParentFile().mkdirs(); // Path p = Paths.get(this.fileName); // File p = Paths.get(this.fileName); File p = new File(this.fileName); // Path dest = Paths.get(destFilePath); // File dest = Paths.get(destFilePath); File dest = new File(destFilePath); // p.copyTo(dest); FileUtils.copyFile(p, dest); } catch (Exception e) { throw new IOException(e); } finally { this.hashlock.unlock(); } } public void move(String destFilePath) throws IOException { this.hashlock.lock(); try { this.sync(); File f = new File(destFilePath); if (f.exists()) f.delete(); else f.getParentFile().mkdirs(); // Path p = Paths.get(this.fileName); File p = new File(this.fileName); // Path dest = Paths.get(destFilePath); File dest = new File(destFilePath); // p.moveTo(dest); FileUtils.moveFile(p, dest); } catch (Exception e) { throw new IOException(e); } finally { this.hashlock.unlock(); } } public void optimize() throws IOException { this.hashlock.lock(); RandomAccessFile rf = null; RandomAccessFile nrf = null; try { log.info("optimizing file [" + this.fileName + "]"); File f = new File(this.fileName + ".new"); f.delete(); rf = new RandomAccessFile(this.fileName, "rw"); nrf = new RandomAccessFile(this.fileName + ".new", "rw"); nrf.setLength(rf.length()); byte[] FREE = new byte[arraySize]; Arrays.fill(FREE, (byte) 0); long mData = 0; for (long pos = 0; pos < rf.length(); pos = pos + this.arraySize) { try { byte[] b = new byte[this.arraySize]; rf.seek(pos); rf.read(b); if (!Arrays.equals(FREE, b)) { nrf.seek(pos); nrf.write(b); mData = mData + b.length; } } catch (Exception e) { e.printStackTrace(); } } rf.close(); rf = null; nrf.close(); nrf = null; File orig = new File(this.fileName); orig.delete(); File newF = new File(this.fileName + ".new"); newF.renameTo(orig); log.info("optimizing file [" + this.fileName + "] migrated [" + mData + "] bytes of data to new file"); } catch (IOException e) { throw e; } finally { if (rf != null) { rf.close(); rf = null; } if (nrf != null) { nrf.close(); nrf = null; } this.hashlock.unlock(); } } }