Author: toad
Date: 2008-01-04 19:25:11 +0000 (Fri, 04 Jan 2008)
New Revision: 16887
Modified:
trunk/freenet/src/freenet/keys/Key.java
trunk/freenet/src/freenet/keys/NodeCHK.java
trunk/freenet/src/freenet/keys/NodeSSK.java
trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
Log:
Write the LRU and key data.
Read it when moving blocks around, when reconstructing etc.
One exception: we still don't reconstruct SSKs yet.
Modified: trunk/freenet/src/freenet/keys/Key.java
===================================================================
--- trunk/freenet/src/freenet/keys/Key.java 2008-01-04 18:22:10 UTC (rev
16886)
+++ trunk/freenet/src/freenet/keys/Key.java 2008-01-04 19:25:11 UTC (rev
16887)
@@ -250,4 +250,7 @@
else //if(key instanceof ClientCHK
return new ClientCHKBlock((CHKBlock)block,
(ClientCHK)key);
}
+
+ /** Get the full key, including any crypto type bytes, everything
needed to construct a Key object */
+ public abstract byte[] getFullKey();
}
Modified: trunk/freenet/src/freenet/keys/NodeCHK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeCHK.java 2008-01-04 18:22:10 UTC (rev
16886)
+++ trunk/freenet/src/freenet/keys/NodeCHK.java 2008-01-04 19:25:11 UTC (rev
16887)
@@ -18,7 +18,7 @@
public class NodeCHK extends Key {
/** 32 bytes for hash, 2 bytes for type */
- public static final short KEY_SIZE_ON_DISK = 34;
+ public static final short FULL_KEY_LENGTH = 34;
public NodeCHK(byte[] routingKey2, byte cryptoAlgorithm) {
super(routingKey2);
@@ -74,4 +74,13 @@
public byte[] getRoutingKey(){
return routingKey;
}
+
+ public byte[] getFullKey() {
+ byte[] buf = new byte[FULL_KEY_LENGTH];
+ short type = getType();
+ buf[0] = (byte) (type >> 8);
+ buf[1] = (byte) (type & 0xFF);
+ System.arraycopy(routingKey, 0, buf, 2, routingKey.length);
+ return buf;
+ }
}
Modified: trunk/freenet/src/freenet/keys/NodeSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeSSK.java 2008-01-04 18:22:10 UTC (rev
16886)
+++ trunk/freenet/src/freenet/keys/NodeSSK.java 2008-01-04 19:25:11 UTC (rev
16887)
@@ -42,6 +42,7 @@
static final int PUBKEY_HASH_SIZE = 32;
static final int E_H_DOCNAME_SIZE = 32;
static final byte BASE_TYPE = 2;
+ public static final int FULL_KEY_LENGTH = 66;
public String toString() {
return
super.toString()+":pkh="+HexUtil.bytesToHex(pubKeyHash)+":ehd="+HexUtil.bytesToHex(encryptedHashedDocname);
@@ -161,5 +162,15 @@
public byte[] getKeyBytes() {
return encryptedHashedDocname;
}
+
+ public byte[] getFullKey() {
+ byte[] buf = new byte[FULL_KEY_LENGTH];
+ short type = getType();
+ buf[0] = (byte) (type >> 8);
+ buf[1] = (byte) (type & 0xFF);
+ System.arraycopy(encryptedHashedDocname, 0, buf, 2,
encryptedHashedDocname.length);
+ System.arraycopy(pubKeyHash, 0, buf, 2+encryptedHashedDocname.length,
pubKeyHash.length);
+ return buf;
+ }
}
Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2008-01-04
18:22:10 UTC (rev 16886)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2008-01-04
19:25:11 UTC (rev 16887)
@@ -136,7 +136,7 @@
int keyLength;
File keysFile;
if(type == TYPE_SSK) {
- keyLength = 32;
+ keyLength = NodeSSK.FULL_KEY_LENGTH;
keysFile = new File(baseStoreDir,
newStoreFileName+".keys");
} else {
keyLength = 0;
@@ -483,6 +483,9 @@
if(len < chkBlocksFromFile) {
System.err.println("Truncating
to "+len+" from "+chkBlocksFromFile+" as no non-holes after that point");
storeRAF.setLength(len *
(dataBlockSize + headerBlockSize));
+ lruRAF.setLength(len * 8);
+ if(keysRAF != null)
+ keysRAF.setLength(len *
keyLength);
blocksInStore = len;
}
}
@@ -541,6 +544,9 @@
System.err.println("Truncating to "+bound+" as
no non-holes after that point");
try {
storeRAF.setLength(bound *
(dataBlockSize + headerBlockSize));
+ lruRAF.setLength(bound * 8);
+ if(keysRAF != null)
+ keysRAF.setLength(bound *
keyLength);
blocksInStore = bound;
for(long l=bound;l<blocksInStore;l++)
freeBlocks.remove(l);
@@ -740,6 +746,8 @@
WrapperManager.signalStarting((int)Math.min(Integer.MAX_VALUE,
(5*60*1000 + wantedMoveNums.length*1000L + alreadyDropped.size() * 100L))); //
1 per second
byte[] buf = new byte[headerBlockSize + dataBlockSize];
+ long lruValue;
+ byte[] keyBuf = new byte[keyLength];
t = null;
try {
t = environment.beginTransaction(null,null);
@@ -786,19 +794,40 @@
DatabaseEntry wantedBlockEntry = new
DatabaseEntry();
LongBinding.longToEntry(wantedBlock.longValue(), wantedBlockEntry);
- long seekTo = wantedBlock.longValue() *
(headerBlockSize + dataBlockSize);
+ long entry = wantedBlock.longValue();
+ boolean readLRU = false;
+ boolean readKey = false;
try {
- storeRAF.seek(seekTo);
+ storeRAF.seek(entry * (headerBlockSize
+ dataBlockSize));
storeRAF.readFully(buf);
+ lruValue = 0;
+ if(lruRAF.length() > ((entry + 1) * 8))
{
+ readLRU = true;
+ lruRAF.seek(entry * 8);
+ lruValue = lruRAF.readLong();
+ }
+ if(keysRAF != null && keysRAF.length()
> ((entry + 1) * keyLength)) {
+ readKey = true;
+ keysRAF.seek(entry * keyLength);
+ keysRAF.readFully(keyBuf);
+ }
} catch (EOFException e) {
System.err.println("Was reading
"+wantedBlock+" to write to "+unwantedBlock);
System.err.println(e);
e.printStackTrace();
throw e;
}
- seekTo = unwantedBlock.longValue() *
(headerBlockSize + dataBlockSize);
- storeRAF.seek(seekTo);
+ entry = unwantedBlock.longValue();
+ storeRAF.seek(entry * (headerBlockSize +
dataBlockSize));
storeRAF.write(buf);
+ if(readLRU) {
+ lruRAF.seek(entry * 8);
+ lruRAF.writeLong(lruValue);
+ }
+ if(readKey) {
+ keysRAF.seek(entry * keyLength);
+ keysRAF.write(keyBuf);
+ }
// Update the database w.r.t. the old block.
@@ -865,6 +894,9 @@
System.out.println("Finishing shrink"); // FIXME remove
storeRAF.setLength(newSize * (dataBlockSize + headerBlockSize));
+ lruRAF.setLength(newSize * 8);
+ if(keysRAF != null)
+ keysRAF.setLength(newSize * keyLength);
synchronized(this) {
blocksInStore = newSize;
@@ -965,6 +997,9 @@
}
storeRAF.setLength(maxBlocksInStore * (dataBlockSize +
headerBlockSize));
+ lruRAF.setLength(maxBlocksInStore * 8);
+ if(keysRAF != null)
+ keysRAF.setLength(maxBlocksInStore * keyLength);
blocksInStore = maxBlocksInStore;
System.err.println("Successfully shrunk store to
"+blocksInStore);
@@ -1113,15 +1148,37 @@
WrapperManager.signalStarting((int)(Math.min(Integer.MAX_VALUE,
5*60*1000+(storeRAF.length()/(dataBlockSize+headerBlockSize))*100)));
byte[] header = new byte[headerBlockSize];
byte[] data = new byte[dataBlockSize];
+ byte[] keyBuf = new byte[keyLength];
long l = 0;
long dupes = 0;
long failures = 0;
try {
storeRAF.seek(0);
+ lruRAF.seek(0);
+ long lruRAFLength = lruRAF.length();
+ long keysRAFLength = 0;
+ if(keysRAF != null) {
+ keysRAF.seek(0);
+ keysRAFLength = keysRAF.length();
+ }
for(l=0;true;l++) {
+ long lruVal;
Transaction t = null;
storeRAF.readFully(header);
storeRAF.readFully(data);
+ if(lruRAFLength > (l+1)*8) {
+ lruVal = lruRAF.readLong();
+ if(lruVal == 0)
+ lruVal = getNewRecentlyUsed();
+ } else {
+ lruVal = getNewRecentlyUsed();
+ }
+ boolean readKey = false;
+ if(keysRAF != null && keysRAFLength >
(l+1)*keyLength) {
+ keysRAF.readFully(keyBuf);
+ readKey = true;
+ }
+ lruVal = lruRAF.readLong();
try {
byte[] routingkey = null;
if(type == TYPE_CHK) {
@@ -1140,11 +1197,14 @@
} else if(type == TYPE_PUBKEY) {
DSAPublicKey key =
DSAPublicKey.create(data);
routingkey = key.asBytesHash();
+ } else if(type == TYPE_SSK && readKey) {
+ // FIXME
+ continue;
} else {
continue;
}
t =
environment.beginTransaction(null,null);
- StoreBlock storeBlock = new
StoreBlock(this, l);
+ StoreBlock storeBlock = new
StoreBlock(this, lruVal);
DatabaseEntry routingkeyDBE = new
DatabaseEntry(routingkey);
DatabaseEntry blockDBE = new
DatabaseEntry();
storeBlockTupleBinding.objectToEntry(storeBlock, blockDBE);
@@ -1177,6 +1237,9 @@
blocksInStore = l;
try {
storeRAF.setLength(size);
+ lruRAF.setLength(l * 8);
+ if(keysRAF != null)
+ keysRAF.setLength(l * keyLength);
} catch (IOException e1) {
System.err.println("Failed to set size");
}
@@ -1272,6 +1335,10 @@
c = null;
t.commit();
t = null;
+ synchronized(storeRAF) {
+ lruRAF.seek(storeBlock.offset *
8);
+
lruRAF.writeLong(storeBlock.recentlyUsed);
+ }
} else {
c.close();
c = null;
@@ -1392,6 +1459,10 @@
c = null;
t.commit();
t = null;
+ synchronized(storeRAF) {
+ lruRAF.seek(storeBlock.offset *
8);
+
lruRAF.writeLong(storeBlock.recentlyUsed);
+ }
} else {
c.close();
c = null;
@@ -1526,6 +1597,10 @@
if(!Arrays.equals(block.asBytesHash(), hash)) {
finishKey(storeBlock, c, t, routingkeyDBE,
hash, replacement);
+ synchronized(storeRAF) {
+ lruRAF.seek(storeBlock.offset * 8);
+
lruRAF.writeLong(storeBlock.recentlyUsed);
+ }
return replacement;
}
@@ -1576,6 +1651,10 @@
storeRAF.seek(storeBlock.offset*(long)(dataBlockSize+headerBlockSize));
byte[] toWrite = replacement.asPaddedBytes();
storeRAF.write(toWrite);
+ if(keysRAF != null) {
+ keysRAF.seek(storeBlock.offset *
keyLength);
+ keysRAF.write(hash);
+ }
}
c.close();
t.commit();
@@ -1634,6 +1713,9 @@
}
}
+ /**
+ * Overwrite an SSK with a new SSK of the same key.
+ */
private boolean overwrite(SSKBlock b) throws IOException {
assert(storeType == TYPE_SSK);
synchronized(this) {
@@ -1669,6 +1751,10 @@
storeRAF.seek(storeBlock.offset*(long)(dataBlockSize+headerBlockSize));
storeRAF.write(header);
storeRAF.write(data);
+ if(keysRAF != null) {
+ keysRAF.seek(storeBlock.offset *
keyLength);
+ keysRAF.write(chk.getFullKey());
+ }
}
// Unlock record.
@@ -1706,6 +1792,7 @@
}
byte[] routingkey = block.getKey().getRoutingKey();
+ byte[] fullKey = keysRAF == null ? null :
block.getKey().getFullKey();
byte[] data = block.getRawData();
byte[] header = block.getRawHeaders();
@@ -1749,7 +1836,7 @@
} else
throw new IllegalStateException("Unknown
operation status: "+result);
- writeBlock(header, data, t, routingkeyDBE);
+ writeBlock(header, data, t, routingkeyDBE, fullKey);
t.commit();
t = null;
@@ -1778,7 +1865,7 @@
return fetch((NodeSSK)key, b);
}
- private void overwriteLRUBlock(byte[] header, byte[] data, Transaction
t, DatabaseEntry routingkeyDBE) throws DatabaseException, IOException {
+ private void overwriteLRUBlock(byte[] header, byte[] data, Transaction
t, DatabaseEntry routingkeyDBE, byte[] fullKey) throws DatabaseException,
IOException {
// Overwrite an other block
Cursor c = accessTimeDB.openCursor(t,null);
DatabaseEntry keyDBE = new DatabaseEntry();
@@ -1797,13 +1884,20 @@
storeRAF.seek(storeBlock.getOffset()*(long)(dataBlockSize+headerBlockSize));
storeRAF.write(header);
storeRAF.write(data);
+ lruRAF.seek(storeBlock.getOffset() * 8);
+ lruRAF.writeLong(storeBlock.recentlyUsed);
+ if(keysRAF != null) {
+ keysRAF.seek(storeBlock.getOffset() *
keyLength);
+ keysRAF.write(fullKey);
+ }
writes++;
}
}
- private boolean writeNewBlock(long blockNum, byte[] header, byte[]
data, Transaction t, DatabaseEntry routingkeyDBE) throws DatabaseException,
IOException {
+ private boolean writeNewBlock(long blockNum, byte[] header, byte[]
data, Transaction t, DatabaseEntry routingkeyDBE, byte[] fullKey) throws
DatabaseException, IOException {
long byteOffset = blockNum*(dataBlockSize+headerBlockSize);
StoreBlock storeBlock = new StoreBlock(this, blockNum);
+ long lruValue = storeBlock.recentlyUsed;
DatabaseEntry blockDBE = new DatabaseEntry();
storeBlockTupleBinding.objectToEntry(storeBlock, blockDBE);
try {
@@ -1839,6 +1933,12 @@
}
storeRAF.write(header);
storeRAF.write(data);
+ lruRAF.seek(blockNum * 8);
+ lruRAF.writeLong(lruValue);
+ if(keysRAF != null) {
+ keysRAF.seek(blockNum * keyLength);
+ keysRAF.write(fullKey);
+ }
writes++;
}
return true;
@@ -1953,7 +2053,7 @@
} else
throw new IllegalStateException("Unknown
operation status: "+result);
- writeBlock(dummy, data, t, routingkeyDBE);
+ writeBlock(dummy, data, t, routingkeyDBE, keysRAF ==
null ? null : hash);
t.commit();
t = null;
@@ -1975,7 +2075,7 @@
}
}
- private void writeBlock(byte[] header, byte[] data, Transaction t,
DatabaseEntry routingkeyDBE) throws DatabaseException, IOException {
+ private void writeBlock(byte[] header, byte[] data, Transaction t,
DatabaseEntry routingkeyDBE, byte[] fullKey) throws DatabaseException,
IOException {
long blockNum;
@@ -1984,7 +2084,7 @@
if((blockNum = grabFreeBlock()) >= 0) {
if(logMINOR)
Logger.minor(this, "Overwriting
free block: "+blockNum);
- if(writeNewBlock(blockNum, header,
data, t, routingkeyDBE))
+ if(writeNewBlock(blockNum, header,
data, t, routingkeyDBE, fullKey))
return;
} else if(blocksInStore<maxBlocksInStore) {
// Expand the store file
@@ -1996,12 +2096,12 @@
Logger.minor(this, "Expanding
store and writing block "+blockNum);
// Just in case
freeBlocks.remove(blockNum);
- if(writeNewBlock(blockNum, header,
data, t, routingkeyDBE))
+ if(writeNewBlock(blockNum, header,
data, t, routingkeyDBE, fullKey))
return;
} else {
if(logMINOR)
Logger.minor(this, "Overwriting
LRU block");
- overwriteLRUBlock(header, data, t,
routingkeyDBE);
+ overwriteLRUBlock(header, data, t,
routingkeyDBE, fullKey);
return;
}
@@ -2144,6 +2244,10 @@
try {
if(storeRAF != null)
storeRAF.close();
+ if(lruRAF != null)
+ lruRAF.close();
+ if(keysRAF != null)
+ keysRAF.close();
} catch (Throwable t) {
if(!(t instanceof RunRecoveryException
|| t instanceof OutOfMemoryError)) {
System.err.println("Caught
closing database: "+t);