package freenet.support.io; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import freenet.client.async.ClientContext; import freenet.crypt.MasterSecret; import freenet.support.api.LockableRandomAccessBuffer; public class DelayedFreeRandomAccessBuffer implements LockableRandomAccessBuffer, Serializable, DelayedFree { private static final long serialVersionUID = 1L; final LockableRandomAccessBuffer underlying; private boolean freed; private transient PersistentFileTracker factory; private transient long createdCommitID; public DelayedFreeRandomAccessBuffer(LockableRandomAccessBuffer raf, PersistentFileTracker factory) { underlying = raf; this.createdCommitID = factory.commitID(); this.factory = factory; } @Override public long size() { return underlying.size(); } @Override public void pread(long fileOffset, byte[] buf, int bufOffset, int length) throws IOException { synchronized(this) { if(freed) throw new IOException("Already freed"); } underlying.pread(fileOffset, buf, bufOffset, length); } @Override public void pwrite(long fileOffset, byte[] buf, int bufOffset, int length) throws IOException { synchronized(this) { if(freed) throw new IOException("Already freed"); } underlying.pwrite(fileOffset, buf, bufOffset, length); } @Override public void close() { synchronized(this) { if(freed) return; } underlying.close(); } @Override public void free() { synchronized(this) { if(freed) return; freed = true; } this.factory.delayedFree(this, createdCommitID); } @Override public RAFLock lockOpen() throws IOException { synchronized(this) { if(freed) throw new IOException("Already freed"); } return underlying.lockOpen(); } @Override public void onResume(ClientContext context) throws ResumeFailedException { this.factory = context.persistentBucketFactory; underlying.onResume(context); } static final int MAGIC = 0x3fb645de; @Override public void storeTo(DataOutputStream dos) throws IOException { dos.writeInt(MAGIC); underlying.storeTo(dos); } public DelayedFreeRandomAccessBuffer(DataInputStream dis, FilenameGenerator fg, PersistentFileTracker persistentFileTracker, MasterSecret masterSecret) throws IOException, StorageFormatException, ResumeFailedException { underlying = BucketTools.restoreRAFFrom(dis, fg, persistentFileTracker, masterSecret); factory = persistentFileTracker; } @Override public boolean toFree() { return freed; } public LockableRandomAccessBuffer getUnderlying() { if(freed) return null; return underlying; } @Override public void realFree() { underlying.free(); } @Override public int hashCode() { return underlying.hashCode(); } /** Two DelayedFreeBucket's for the same underlying can only happen on resume, in which case * we DO want them to compare as equal. */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DelayedFreeRandomAccessBuffer other = (DelayedFreeRandomAccessBuffer) obj; return underlying.equals(other.underlying); } }