Author: j16sdiz
Date: 2008-07-07 15:52:14 +0000 (Mon, 07 Jul 2008)
New Revision: 21000

Modified:
   
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
   
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
Log:
new store file format: split meta-data, header and data
cleaner temporary disabled

Modified: 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
===================================================================
--- 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
    2008-07-07 15:51:48 UTC (rev 20999)
+++ 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/CipherManager.java
    2008-07-07 15:52:14 UTC (rev 21000)
@@ -111,6 +111,9 @@
         * @return <code>true</code> if the <code>routeKey</code> match and the 
entry is decrypted.
         */
        boolean decrypt(SaltedHashFreenetStore.Entry entry, byte[] routingKey) {
+               assert entry.header != null;
+               assert entry.data != null;
+
                if (!entry.isEncrypted) {
                        // Already decrypted
                        if (Arrays.equals(entry.plainRoutingKey, routingKey))

Modified: 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
===================================================================
--- 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
   2008-07-07 15:51:48 UTC (rev 20999)
+++ 
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
   2008-07-07 15:52:14 UTC (rev 21000)
@@ -9,7 +9,6 @@
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.text.DecimalFormat;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -46,6 +45,7 @@
  * @author sdiz
  */
 public class SaltedHashFreenetStore implements FreenetStore {
+       /** Option for saving plainkey */
        private static final boolean OPTION_SAVE_PLAINKEY = true;
        private static final int OPTION_MAX_PROBE = 4;

@@ -71,8 +71,8 @@
        private final int dataBlockLength;
        private final Random random;
        private long storeSize;
-       private byte generation;
-       private byte flags;
+       private int generation;
+       private int flags;

        public static SaltedHashFreenetStore construct(File baseDir, String 
name, StoreCallback callback, Random random,
                        long maxKeys, SemiOrderedShutdownHook shutdownHook) 
throws IOException {
@@ -97,10 +97,6 @@
                this.random = random;
                storeSize = maxKeys;

-               long length = ENTRY_HEADER_LENGTH + headerBlockLength + 
dataBlockLength;
-               entryPaddingLength = 0x200L - (length % 0x200L);
-               entryTotalLength = length + entryPaddingLength;
-
                lockManager = new LockManager();

                // Create a directory it not exist
@@ -152,7 +148,7 @@
                                return null;
                        }
                        try {
-                               Entry entry = probeEntry(routingKey);
+                               Entry entry = probeEntry(routingKey, true);

                                if (entry == null) {
                                        misses.incrementAndGet();
@@ -181,25 +177,26 @@
         * lock the entries.
         * 
         * @param routingKey
+        * @param withData
         * @return <code>Entry</code> object
         * @throws IOException
         */
-       private Entry probeEntry(byte[] routingKey) throws IOException {
+       private Entry probeEntry(byte[] routingKey, boolean withData) throws 
IOException {
                if (checkBloom)
                        if 
(!bloomFilter.checkFilter(cipherManager.getDigestedKey(routingKey)))
                                return null;

-               Entry entry = probeEntry0(routingKey, storeSize);
+               Entry entry = probeEntry0(routingKey, storeSize, withData);

                if (entry == null && prevStoreSize != 0)
-                       entry = probeEntry0(routingKey, prevStoreSize);
+                       entry = probeEntry0(routingKey, prevStoreSize, 
withData);
                if (checkBloom && entry == null)
                        bloomFalsePos.incrementAndGet();

                return entry;
        }

-       private Entry probeEntry0(byte[] routingKey, long probeStoreSize) 
throws IOException {
+       private Entry probeEntry0(byte[] routingKey, long probeStoreSize, 
boolean withData) throws IOException {
                Entry entry = null;
                long[] offset = getOffsetFromPlainKey(routingKey, 
probeStoreSize);

@@ -208,7 +205,7 @@
                                Logger.debug(this, "probing for i=" + i + ", 
offset=" + offset[i]);

                        try {
-                               entry = readEntry(offset[i], routingKey);
+                               entry = readEntry(offset[i], routingKey, 
withData);
                                if (entry != null)
                                        return entry;
                        } catch (EOFException e) {
@@ -234,19 +231,23 @@
                                return;
                        }
                        try {
-                               // don't use fetch(), as fetch() would do a 
miss++/hit++
-                               Entry oldEntry = probeEntry(routingKey);
+                               /*
+                                * Use lazy loading here. This may lost data if 
digestedRoutingKey collide but
+                                * collisionPossible is false. Should be very 
rare as digestedRoutingKey is a
+                                * SHA-256 hash.
+                                */
+                               Entry oldEntry = probeEntry(routingKey, false);
                                if (oldEntry != null) {
                                        long oldOffset = oldEntry.curOffset;
                                        try {
-                                               StorableBlock oldBlock = 
oldEntry.getStorableBlock(routingKey, fullKey);
                                                if (!collisionPossible)
                                                        return;
+                                               
oldEntry.setData(readHeader(oldOffset), readData(oldOffset)); // read from disk
+                                               StorableBlock oldBlock = 
oldEntry.getStorableBlock(routingKey, fullKey);
                                                if (block.equals(oldBlock)) {
                                                        return; // already in 
store
-                                               } else {
-                                                       if (!overwrite)
-                                                               throw new 
KeyCollisionException();
+                                               } else if (!overwrite) {
+                                                       throw new 
KeyCollisionException();
                                                }
                                        } catch (KeyVerifyException e) {
                                                // ignore
@@ -256,7 +257,7 @@
                                        Entry entry = new Entry(routingKey, 
header, data);
                                        writeEntry(entry, oldOffset);
                                        writes.incrementAndGet();
-                                       if (oldEntry.getGeneration() != 
generation)
+                                       if (oldEntry.generation != generation)
                                                keyCount.incrementAndGet();
                                        return;
                                }
@@ -284,10 +285,10 @@
                                        Logger.debug(this, "collision, write to 
i=0, offset=" + offset[0]);
                                if (updateBloom)
                                        
bloomFilter.updateFilter(cipherManager.getDigestedKey(routingKey));
-                               oldEntry = readEntry(offset[0], null);
+                               oldEntry = readEntry(offset[0], null, false);
                                writeEntry(entry, offset[0]);
                                writes.incrementAndGet();
-                               if (oldEntry.getGeneration() != generation)
+                               if (oldEntry.generation != generation)
                                        keyCount.incrementAndGet();
                        } finally {
                                unlockPlainKey(routingKey, false);
@@ -298,27 +299,24 @@
        }

        // ------------- Entry I/O
+       // meta-data file
+       private File metaFile;
+       private RandomAccessFile metaRAF;
+       private FileChannel metaFC;
+       // header file
+       private File headerFile;
+       private RandomAccessFile headerRAF;
+       private FileChannel headerFC;
+       // data file
+       private File dataFile;
+       private RandomAccessFile dataRAF;
+       private FileChannel dataFC;

-       // split the files for better concurrency
-       // you may even some if you have lots of mount points =)
-       private final static int FILE_SPLIT = 0x04;
-       private File[] storeFiles;
-       private RandomAccessFile[] storeRAF;
-       private FileChannel[] storeFC;
-
-       /** Flag for occupied space */
-       private final long ENTRY_FLAG_OCCUPIED = 0x00000001L;
-       /** Flag for plain key available */
-       private final long ENTRY_FLAG_PLAINKEY = 0x00000002L;
-
-       private static final long ENTRY_HEADER_LENGTH = 0x70L;
-       private final long entryPaddingLength;
-       private final long entryTotalLength;
-
        /**
         * Data entry
         * 
         * <pre>
+        *  META-DATA BLOCK
         *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         *       |0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|
         *  +----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -332,47 +330,96 @@
         *  +----+---------------+---------------+
         *  |0040|       Plain Routing Key       |
         *  |0050| (Only if ENTRY_FLAG_PLAINKEY) |
-        *  +----+-+-----------------------------+
-        *  |0060|G|          Reserved           |
-        *  +----+-+-----------------------------+
-        *  |0070|       Encrypted Header        |
-        *  |  . + - - - - - - - - - - - - - - - +
-        *  |  . |        Encrypted Data         |
+        *  +----+-------+-----------------------+
+        *  |0060|  Gen  |    Reserved           |
+        *  +----+-------+-----------------------+
+        *  |0070|            Reserved           |
         *  +----+-------------------------------+
-        *  |    |           Padding             |
-        *  +----+-------------------------------+
+        *  
+        *  Gen = Generation
         * </pre>
-        * 
-        * Total length is padded to multiple of 512bytes. All reserved bytes 
should be zero when
-        * written, ignored on read.
         */
-        class Entry {
+       class Entry {
+               /** Flag for occupied space */
+               private final static long ENTRY_FLAG_OCCUPIED = 0x00000001L;
+               /** Flag for plain key available */
+               private final static long ENTRY_FLAG_PLAINKEY = 0x00000002L;
+
+               /** Control block length */
+               private static final int METADATA_LENGTH = 0x80;
+
                byte[] plainRoutingKey;
                byte[] digestedRoutingKey;
                byte[] dataEncryptIV;
                private long flag;
                private long storeSize;
-               private byte generation;
+               private int generation;
                byte[] header;
                byte[] data;
-               
+
                boolean isEncrypted;
-               public long curOffset = -1;
-               
+               private long curOffset = -1;

+               private Entry() {
+               }
+
+               private Entry(ByteBuffer metaDataBuf, ByteBuffer headerBuf, 
ByteBuffer dataBuf) {
+                       assert metaDataBuf.remaining() == METADATA_LENGTH;
+
+                       digestedRoutingKey = new byte[0x20];
+                       metaDataBuf.get(digestedRoutingKey);
+
+                       dataEncryptIV = new byte[0x10];
+                       metaDataBuf.get(dataEncryptIV);
+
+                       flag = metaDataBuf.getLong();
+                       storeSize = metaDataBuf.getLong();
+
+                       if ((flag & ENTRY_FLAG_PLAINKEY) != 0) {
+                               plainRoutingKey = new byte[0x20];
+                               metaDataBuf.get(plainRoutingKey);
+                       }
+
+                       metaDataBuf.position(0x60);
+                       generation = metaDataBuf.getInt();
+
+                       isEncrypted = true;
+
+                       if (headerBuf != null && dataBuf != null)
+                               setData(headerBuf, dataBuf);
+               }
+
                /**
+                * Set header/data after construction.
+                * 
+                * @param storeBuf
+                * @param store
+                */
+               private void setData(ByteBuffer headerBuf, ByteBuffer dataBuf) {
+                       assert headerBuf.remaining() == headerBlockLength;
+                       assert dataBuf.remaining() == dataBlockLength;
+                       assert isEncrypted;
+
+                       header = new byte[headerBlockLength];
+                       headerBuf.get(header);
+
+                       data = new byte[dataBlockLength];
+                       dataBuf.get(data);
+               }
+
+               /**
                 * Create a new entry
-                *
+                * 
                 * @param plainRoutingKey
                 * @param header
                 * @param data
                 */
-               public Entry(byte[] plainRoutingKey, byte[] header, byte[] 
data) {
+               private Entry(byte[] plainRoutingKey, byte[] header, byte[] 
data) {
                        this.plainRoutingKey = plainRoutingKey;

                        flag = ENTRY_FLAG_OCCUPIED;
-                       storeSize = SaltedHashFreenetStore.this.storeSize;
-                       generation = SaltedHashFreenetStore.this.generation;
+                       this.storeSize = SaltedHashFreenetStore.this.storeSize;
+                       this.generation = 
SaltedHashFreenetStore.this.generation;

                        // header/data will be overwritten in 
encrypt()/decrypt(),
                        // let's make a copy here
@@ -388,87 +435,50 @@
                        isEncrypted = false;
                }

-               /**
-                * @return the storeSize
-                */
-               protected long getStoreSize() {
-                       return storeSize;
-               }
-
-               /**
-                * @param storeSize
-                *              the storeSize to set
-                */
-               protected void setStoreSize(long storeSize) {
-                       this.storeSize = storeSize;
-               }
-
-               public Entry(ByteBuffer in) {
-                       assert in.remaining() == entryTotalLength;
-
-                       digestedRoutingKey = new byte[0x20];
-                       in.get(digestedRoutingKey);
-
-                       dataEncryptIV = new byte[0x10];
-                       in.get(dataEncryptIV);
-
-                       flag = in.getLong();
-                       storeSize = in.getLong();
-
-                       if ((flag & ENTRY_FLAG_PLAINKEY) != 0) {
-                               plainRoutingKey = new byte[0x20];
-                               in.get(plainRoutingKey);
-                       }
-
-                       in.position(0x60);
-                       generation = in.get();
-                       
-                       // reserved bytes
-                       in.position((int) ENTRY_HEADER_LENGTH);
-
-                       header = new byte[headerBlockLength];
-                       in.get(header);
-
-                       data = new byte[dataBlockLength];
-                       in.get(data);
-
-                       assert in.remaining() == entryPaddingLength;
-
-                       isEncrypted = true;
-               }
-
-               private Entry() {
-        }
-
-               public ByteBuffer toByteBuffer() {
-                       ByteBuffer out = ByteBuffer.allocate((int) 
entryTotalLength);
+               private ByteBuffer toMetaDataBuffer() {
+                       ByteBuffer out = ByteBuffer.allocate(METADATA_LENGTH);
                        cipherManager.encrypt(this, random);
+
                        out.put(getDigestedRoutingKey());
                        out.put(dataEncryptIV);
-
                        out.putLong(flag);
                        out.putLong(storeSize);

-                       if (OPTION_SAVE_PLAINKEY && plainRoutingKey != null) {
+                       if ((flag & ENTRY_FLAG_PLAINKEY) != 0 && 
plainRoutingKey != null) {
+                               assert plainRoutingKey.length == 0x20;
                                out.put(plainRoutingKey);
                        }
-                       
+
                        out.position(0x60);
-                       out.put(generation);
-                       
-                       // reserved bytes
-                       out.position((int) ENTRY_HEADER_LENGTH);
+                       out.putInt(generation);

+                       out.position(0);
+                       return out;
+               }
+
+               private ByteBuffer toHeaderBuffer() {
+                       assert isEncrypted; // should have encrypted to get 
dataEncryptIV in control buffer
+
+                       ByteBuffer out = ByteBuffer.allocate(headerBlockLength);
                        out.put(header);
-                       out.put(data);
+                       assert out.remaining() == 0;

-                       assert out.remaining() == entryPaddingLength;
                        out.position(0);
+                       return out;
+               }

+               private ByteBuffer toDataBuffer() {
+                       assert isEncrypted; // should have encrypted to get 
dataEncryptIV in control buffer
+
+                       ByteBuffer out = ByteBuffer.allocate(dataBlockLength);
+                       out.put(data);
+                       assert out.remaining() == 0;
+
+                       out.position(0);
                        return out;
                }

-               public StorableBlock getStorableBlock(byte[] routingKey, byte[] 
fullKey) throws KeyVerifyException {
+               private StorableBlock getStorableBlock(byte[] routingKey, 
byte[] fullKey) throws KeyVerifyException {
                        if ((flag & ENTRY_FLAG_OCCUPIED) == 0)
                                return null; // this is a free block
                        if (!cipherManager.decrypt(this, routingKey))
@@ -478,7 +488,6 @@
                        byte[] blockRoutingKey = block.getRoutingKey();

                        if (!Arrays.equals(blockRoutingKey, routingKey)) {
-                               // either the data is corrupted or we have 
found a SHA-1 collision
                                // can't recover, as decrypt() depends on a 
correct route key
                                return null;
                        }
@@ -486,206 +495,191 @@
                        return block;
                }

-               public long[] getOffset() {
+               private long[] getOffset() {
                        if (digestedRoutingKey != null)
                                return 
getOffsetFromDigestedKey(digestedRoutingKey, storeSize);
                        else
                                return getOffsetFromPlainKey(plainRoutingKey, 
storeSize);
                }

-               public boolean isFree() {
+               private boolean isFree() {
                        return (flag & ENTRY_FLAG_OCCUPIED) == 0;
                }

-               public byte[] getDigestedRoutingKey() {
+               byte[] getDigestedRoutingKey() {
                        if (digestedRoutingKey == null)
-                               digestedRoutingKey = 
cipherManager.getDigestedKey(plainRoutingKey);
+                               if (plainRoutingKey == null)
+                                       return null;
+                               else
+                                       digestedRoutingKey = 
cipherManager.getDigestedKey(plainRoutingKey);
                        return digestedRoutingKey;
                }
-
-               public byte getGeneration() {
-                       return generation;
-               }
-
-               public void setGeneration(byte generation) {
-                       this.generation = generation;
-               }
        }

        /**
         * Open all store files
-        *
+        * 
         * @param baseDir
         * @param name
         * @throws IOException
         */
        private void openStoreFiles(File baseDir, String name) throws 
IOException {
-               storeFiles = new File[FILE_SPLIT];
-               storeRAF = new RandomAccessFile[FILE_SPLIT];
-               storeFC = new FileChannel[FILE_SPLIT];
+               metaFile = new File(baseDir, name + ".metadata");
+               metaRAF = new RandomAccessFile(metaFile, "rw");
+               metaFC = metaRAF.getChannel();
+               metaFC.lock();

-               DecimalFormat fmt = new DecimalFormat("000");
-               for (int i = 0; i < FILE_SPLIT; i++) {
-                       storeFiles[i] = new File(baseDir, name + ".data-" + 
fmt.format(i));
+               headerFile = new File(baseDir, name + ".header");
+               headerRAF = new RandomAccessFile(headerFile, "rw");
+               headerFC = headerRAF.getChannel();
+               headerFC.lock();

-                       storeRAF[i] = new RandomAccessFile(storeFiles[i], "rw");
+               dataFile = new File(baseDir, name + ".data");
+               dataRAF = new RandomAccessFile(dataFile, "rw");
+               dataFC = dataRAF.getChannel();
+               dataFC.lock();

-                       storeFC[i] = storeRAF[i].getChannel();
-                       storeFC[i].lock();
-               }
-
                long storeFileSize = Math.max(storeSize, prevStoreSize);
                setStoreFileSize(storeFileSize);
        }

        /**
-        * Flush all store files to disk
-        */
-       private void flushStoreFiles() {
-               for (int i = 0; i < FILE_SPLIT; i++) {
-                       try {
-                               storeFC[i].force(true);
-                       } catch (Exception e) {
-                               Logger.normal(this, "error flushing store 
file", e);
-                       }
-               }
-       }
-
-       /**
         * Read entry from disk.
         *
         * Before calling this function, you should acquire all required locks.
         */
-       private Entry readEntry(long offset, byte[] routingKey) throws 
IOException {
-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;
+       private Entry readEntry(long offset, byte[] routingKey, boolean 
withData) throws IOException {
+               ByteBuffer mbf = ByteBuffer.allocate(Entry.METADATA_LENGTH);

-               ByteBuffer bf = ByteBuffer.allocate((int) entryTotalLength);
                do {
-                       int status = storeFC[split].read(bf, rawOffset + 
bf.position());
+                       int status = metaFC.read(mbf, Entry.METADATA_LENGTH * 
offset + mbf.position());
                        if (status == -1)
                                throw new EOFException();
-               } while (bf.hasRemaining());
-               bf.flip();
+               } while (mbf.hasRemaining());
+               mbf.flip();

-               Entry entry = new Entry(bf);
-
+               Entry entry = new Entry(mbf, null, null);
+               entry.curOffset = offset;
+               
                if (routingKey != null) {
-                       boolean decrypted = cipherManager.decrypt(entry, 
routingKey);
-                       if (!decrypted)
+                       if (!Arrays.equals(routingKey, 
entry.digestedRoutingKey))
                                return null;
+                       if (withData) {
+                               ByteBuffer headerBuf = readHeader(offset);
+                               ByteBuffer dataBuf = readData(offset);
+                               entry.setData(headerBuf, dataBuf);
+                               boolean decrypted = 
cipherManager.decrypt(entry, routingKey);
+                               if (!decrypted)
+                                       return null;
+                       }
                }

-               entry.curOffset = offset;
                return entry;
        }

        /**
-        * Write entry to disk.
-        *
-        * Before calling this function, you should:
-        * <ul>
-        * <li>acquire all required locks</li>
-        * <li>update the entry with latest store size</li>
-        * </ul>
+        * Read header from disk
+        * 
+        * @param offset
+        * @throws IOException
         */
-       private void writeEntry(Entry entry, long offset) throws IOException {
-               cipherManager.encrypt(entry, random);
+       private ByteBuffer readHeader(long offset) throws IOException {
+               ByteBuffer buf = ByteBuffer.allocate(headerBlockLength);

-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;
-
-               ByteBuffer bf = entry.toByteBuffer();
                do {
-                       int status = storeFC[split].write(bf, rawOffset + 
bf.position());
+                       int status = headerFC.read(buf, headerBlockLength * 
offset + buf.position());
                        if (status == -1)
                                throw new EOFException();
-               } while (bf.hasRemaining());
+               } while (buf.hasRemaining());

-               entry.curOffset = offset;
+               return buf;
        }

        /**
-        * Free an entry by zeroing the header
-        *
+        * Read data from disk
+        * 
         * @param offset
         * @throws IOException
         */
-       private void freeOffset(long offset) throws IOException {
-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;
+       private ByteBuffer readData(long offset) throws IOException {
+               ByteBuffer buf = ByteBuffer.allocate(dataBlockLength);

-               ByteBuffer bf = ByteBuffer.allocate(0x200); // 512 bytes, one 
physical disk block
                do {
-                       int status = storeFC[split].write(bf, rawOffset + 
bf.position());
+                       int status = dataFC.read(buf, dataBlockLength * offset 
+ buf.position());
                        if (status == -1)
                                throw new EOFException();
-               } while (bf.hasRemaining());
+               } while (buf.hasRemaining());
+
+               return buf;
        }

-       /**
-        * Get store size
-        */
-       private long getStoreSize(long offset) throws IOException {
-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength + 
0x38;
+       private boolean isFree(long offset) throws IOException {
+               Entry entry = readEntry(offset, null, false);
+               return entry.isFree();
+       }

-               ByteBuffer bf = ByteBuffer.allocate(0x8);
-
-               do {
-                       int status = storeFC[split].read(bf, rawOffset + 
bf.position());
-                       if (status == -1)
-                               throw new EOFException();
-               } while (bf.hasRemaining());
-
-               return bf.getLong(0);
+       private byte[] getDigestedKeyFromOffset(long offset) throws IOException 
{
+               Entry entry = readEntry(offset, null, false);
+               return entry.getDigestedRoutingKey();
        }

        /**
-        * Check if a block is free
+        * Write entry to disk.
         *
-        * @param offset
-        * @throws IOException
+        * Before calling this function, you should:
+        * <ul>
+        * <li>acquire all required locks</li>
+        * <li>update the entry with latest store size</li>
+        * </ul>
         */
-       private boolean isFree(long offset) throws IOException {
-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength + 
0x30;
+       private void writeEntry(Entry entry, long offset) throws IOException {
+               cipherManager.encrypt(entry, random);

-               ByteBuffer bf = ByteBuffer.allocate(0x8);
-
+               ByteBuffer bf = entry.toMetaDataBuffer();
                do {
-                       int status = storeFC[split].read(bf, rawOffset + 
bf.position());
+                       int status = metaFC.write(bf, Entry.METADATA_LENGTH * 
offset + bf.position());
                        if (status == -1)
                                throw new EOFException();
                } while (bf.hasRemaining());

-               return ((bf.getLong(0) & ENTRY_FLAG_OCCUPIED) == 0);
-       }
-       
-       private byte[] getDigestedKeyFromOffset(long offset) throws IOException 
{
-               int split = (int) (offset % FILE_SPLIT);
-               long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;
-
-               ByteBuffer bf = ByteBuffer.wrap(new byte[0x20]);
-
+               bf = entry.toHeaderBuffer();
+               if (bf != null) {
                do {
-                       int status = storeFC[split].read(bf, rawOffset + 
bf.position());
+                               int status = headerFC.write(bf, 
headerBlockLength * offset + bf.position());
+                               if (status == -1)
+                                       throw new EOFException();
+                       } while (bf.hasRemaining());
+
+                       bf = entry.toDataBuffer();
+                       do {
+                               int status = dataFC.write(bf, dataBlockLength * 
offset + bf.position());
                        if (status == -1)
                                throw new EOFException();
                } while (bf.hasRemaining());
+               }

-               return bf.array();
+               entry.curOffset = offset;
        }

        private void flushAndClose() {
-               for (int i = 0; i < FILE_SPLIT; i++) {
                        try {
-                               storeFC[i].force(true);
-                               storeFC[i].close();
+                       metaFC.force(true);
+                       metaFC.close();
                        } catch (Exception e) {
                                Logger.error(this, "error flusing store", e);
                        }
+               try {
+                       headerFC.force(true);
+                       headerFC.close();
+               } catch (Exception e) {
+                       Logger.error(this, "error flusing store", e);
                }
+               try {
+                       dataFC.force(true);
+                       dataFC.close();
+               } catch (Exception e) {
+                       Logger.error(this, "error flusing store", e);
+               }

                if (bloomFilter != null)
                        bloomFilter.force();
@@ -697,14 +691,14 @@
         * @param storeFileSize
         */
        private void setStoreFileSize(long storeFileSize) {
-               for (int i = 0; i < FILE_SPLIT; i++) {
                        try {
-                               storeRAF[i].setLength(entryTotalLength * 
(storeFileSize / FILE_SPLIT + 1));
+                       metaRAF.setLength(Entry.METADATA_LENGTH * 
storeFileSize);
+                       headerRAF.setLength(headerBlockLength * storeFileSize);
+                       dataRAF.setLength(dataBlockLength * storeFileSize);
                        } catch (IOException e) {
                                Logger.error(this, "error resizing store file", 
e);
                        }
                }
-       }

        // ------------- Configuration
        /**
@@ -717,12 +711,11 @@
         *  |0000|             Salt              |
         *  +----+---------------+---------------+
         *  |0010|   Store Size  | prevStoreSize |
-        *  +----+---------------+-+-+-----------+
-        *  |0020| Est Key Count |G|F|  reserved |
-        *  +----+---------------+-+-+-----------+
+        *  +----+---------------+-------+-------+
+        *  |0020| Est Key Count |  Gen  | Flags |
+        *  +----+---------------+-------+-------+
         *  
-        *  G = Generation
-        *  F = Flags
+        *  Gen = Generation
         * </pre>
         */
        private final File configFile;
@@ -750,8 +743,8 @@
                        storeSize = raf.readLong();
                        prevStoreSize = raf.readLong();
                        keyCount.set(raf.readLong());
-                       generation = raf.readByte();
-                       flags = raf.readByte();
+                       generation = raf.readInt();
+                       flags = raf.readInt();

                        if ((flags & FLAG_DIRTY) != 0)
                                flags |= FLAG_REBUILD_BLOOM;
@@ -775,9 +768,8 @@
                        raf.writeLong(storeSize);
                        raf.writeLong(prevStoreSize);
                        raf.writeLong(keyCount.get());
-                       raf.write(generation);
-                       raf.write(flags);
-                       raf.setLength(0x30);
+                       raf.writeInt(generation);
+                       raf.writeInt(flags);

                        raf.close();

@@ -868,20 +860,20 @@
                }

                private static final int RESIZE_MEMORY_ENTRIES = 256; // 
temporary memory store size (in # of entries)
-               private static final int RESIZE_DISK_ENTRIES = 8192; // 
temporary disk store size (in # of entries)

                /**
                 * Move old entries to new location and resize store
                 */
                private void resizeStore(long _prevStoreSize) {
+                       if (true) // temporary disabled
+                               return;
+
                        Logger.normal(this, "Starting datastore resize");
                        long startTime = System.currentTimeMillis();

                        if (storeSize > _prevStoreSize)
                                setStoreFileSize(storeSize);

-                       initOldEntriesFile();
-
                        configLock.writeLock().lock();
                        try {
                                generation++;
@@ -904,10 +896,10 @@

                                batchProcessEntries(curOffset, 
RESIZE_MEMORY_ENTRIES, new BatchProcessor() {
                                        public Entry process(Entry entry) {
-                                               entry.setGeneration(generation);
+                                               entry.generation = generation;
                                                keyCount.incrementAndGet();

-                                               if (entry.getStoreSize() == 
storeSize) {// new size
+                                               if (entry.storeSize == 
storeSize) {// new size
                                                        
bloomFilter.updateFilter(entry.getDigestedRoutingKey());

                                                        return entry;
@@ -928,20 +920,11 @@
                                                it.remove();
                                }

-                               // write unresolved entry to file
-                               it = oldEntryList.listIterator();
-                               while (it.hasNext()) {
-                                       rrWriteOldEntry(it.next());
-                                       it.remove();
-                               }
-                               
                                long processed = _prevStoreSize - curOffset;
                                if (i++ % 16 == 0)
                                        Logger.normal(this, "Store resize (" + 
name + "): " + processed + "/" + _prevStoreSize);
                        }

-                       resolveOldEntriesFile();
-
                        long endTime = System.currentTimeMillis();
                        Logger.normal(this, "Finish resizing (" + name + ") in 
" + (endTime - startTime) / 1000 + "s");

@@ -961,6 +944,9 @@
                 * Rebuild bloom filter
                 */
                private void rebuildBloom() {
+                       if (true) // temporary disabled
+                               return;
+
                        if (bloomFilter == null)
                                return;

@@ -984,11 +970,11 @@
                                }
                                batchProcessEntries(curOffset, 
RESIZE_MEMORY_ENTRIES, new BatchProcessor() {
                                        public Entry process(Entry entry) {
-                                               if (entry.getGeneration() != 
generation) {
+                                               if (entry.generation != 
generation) {
                                                        
bloomFilter.updateFilter(entry.getDigestedRoutingKey());
                                                        
keyCount.incrementAndGet();

-                                                       
entry.setGeneration(generation);
+                                                       entry.generation = 
generation;
                                                        return entry;
                                                }
                                                return NOT_MODIFIED;
@@ -1028,6 +1014,9 @@
                 *         otherwise (e.g. can't acquire locks, node shutting 
down)
                 */
                private boolean batchProcessEntries(long offset, int length, 
BatchProcessor processor) {
+                       return false;
+
+                       /*- temporary disabled
                        assert offset % FILE_SPLIT == 0;
                        assert length % FILE_SPLIT == 0;

@@ -1074,7 +1063,7 @@
                                                        ByteBuffer enBuf = 
buf.slice();
                                                        enBuf.limit((int) 
entryTotalLength);

-                                                       Entry entry = new 
Entry(enBuf);
+                                                       Entry entry = new 
Entry(enBuf, SaltedHashFreenetStore.this);
                                                        entry.curOffset = 
offset + j * FILE_SPLIT + i;

                                                        if (entry.isFree())
@@ -1091,7 +1080,7 @@
                                                        } else {
                                                                // write back
                                                                
buf.position((int) (j * entryTotalLength));
-                                                               
buf.put(newEntry.toByteBuffer());
+                                                               
buf.put(newEntry.toByteBuffer(SaltedHashFreenetStore.this));
                                                                dirty = true;
                                                        } 
                                                }
@@ -1118,6 +1107,7 @@
                                        if (locked[i])
                                                lockManager.unlockEntry(offset 
+ i);
                        }
+                        */
                }

                /**
@@ -1130,7 +1120,7 @@
                        if (!lockDigestedKey(entry.getDigestedRoutingKey(), 
false))
                                return false;
                        try {
-                               entry.setStoreSize(storeSize);
+                               entry.storeSize = storeSize;
                                long[] offsets = entry.getOffset();

                                // Check for occupied entry with same key
@@ -1164,73 +1154,6 @@
                                
unlockDigestedKey(entry.getDigestedRoutingKey(), false);
                        }
                }
-
-               private File oldEntriesFile; // round-ribbon
-               private RandomAccessFile oldEntriesRAF;
-               private long oldEntriesFileOffset;
-
-               private void initOldEntriesFile() {
-                       try {
-                               oldEntriesFile = new File(baseDir, name + 
".oldEntries");
-                               oldEntriesRAF = new 
RandomAccessFile(oldEntriesFile, "rw");
-                               oldEntriesRAF.setLength(RESIZE_DISK_ENTRIES * 
entryTotalLength);
-                               oldEntriesFileOffset = 0;
-                       } catch (IOException ioe) {
-                               Logger.error(this, "Cannot create oldEntries 
file for resize, will use memory only", ioe);
-                       }
-               }
-
-               private void resolveOldEntriesFile() {
-                       if (oldEntriesRAF == null)
-                               return;
-
-                       for (int offset = 0; offset < RESIZE_DISK_ENTRIES; 
offset++) {
-                               Entry oldEntry = readOldEntry(offset);
-                               if (oldEntry != null && !oldEntry.isFree()) // 
the current position already in use
-                                       resolveOldEntry(oldEntry);
-                       }
-                       try {
-                               oldEntriesRAF.close();
-                       } catch (IOException ioe) {
-                               // ignore
-                       }
-                       oldEntriesFile.delete();
-               }
-
-               private void rrWriteOldEntry(Entry entry) {
-                       if (oldEntriesRAF == null)
-                               return;
-
-                       long offset = oldEntriesFileOffset++ % 
RESIZE_DISK_ENTRIES;
-                       Entry rrOldEntry = readOldEntry(offset);
-                       if (rrOldEntry != null && !rrOldEntry.isFree()) // the 
current position already in use
-                               resolveOldEntry(rrOldEntry);
-
-                       byte[] buf = new byte[(int) entryTotalLength];
-                       entry.toByteBuffer().get(buf);
-                       try {
-                               oldEntriesRAF.seek(offset * entryTotalLength);
-                               oldEntriesRAF.write(buf);
-                       } catch (IOException e) {
-                               Logger.debug(this, "IOException on 
rrWriteOldEntry", e);
-                       }
-               }
-
-               private Entry readOldEntry(long offset) {
-                       if (oldEntriesRAF == null)
-                               return null;
-
-                       try { 
-                               byte[] buf = new byte[(int) entryTotalLength];
-                               oldEntriesRAF.seek(offset * entryTotalLength);
-                               oldEntriesRAF.readFully(buf);
-
-                               return new Entry(ByteBuffer.wrap(buf));
-                       } catch (IOException e) {
-                               Logger.debug(this, "IOException on 
readOldEntry", e);
-                               return null;
-                       }
-               }
        }

        public void setMaxKeys(long newStoreSize, boolean shrinkNow) throws 
IOException {
@@ -1358,7 +1281,6 @@
        // ------------- Hashing
        private CipherManager cipherManager;

-
        /**
         * Get offset in the hash table, given a plain routing key.
         *


Reply via email to