Author: toad
Date: 2008-10-31 18:13:07 +0000 (Fri, 31 Oct 2008)
New Revision: 23264
Modified:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketTag.java
Log:
db4o doesn't like looking up a null in an index, so add an explicit isFree
variable.
Optimise adding blocks after extending file, one query instead of one per block
(up to 16384).
Modified:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
===================================================================
---
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
2008-10-31 18:11:45 UTC (rev 23263)
+++
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
2008-10-31 18:13:07 UTC (rev 23264)
@@ -5,7 +5,9 @@
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
@@ -81,21 +83,36 @@
return storageFile.getPath();
}
+ static final int MAX_FREE = 2048;
+
private final DBJob slotFinder = new DBJob() {
public void run(ObjectContainer container, ClientContext
context) {
boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
synchronized(PersistentBlobTempBucketFactory.this) {
- if(freeSlots.size() > 1024) return;
+ if(freeSlots.size() > MAX_FREE) return;
}
Query query = container.query();
-
query.constrain(PersistentBlobTempBucketTag.class).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this).and(query.descend("bucket").constrain(null)));
+ query.constrain(PersistentBlobTempBucketTag.class);
+ query.descend("isFree").constrain(true);
ObjectSet<PersistentBlobTempBucketTag> tags =
query.execute();
Long[] notCommitted;
int added = 0;
synchronized(PersistentBlobTempBucketFactory.this) {
while(tags.hasNext()) {
PersistentBlobTempBucketTag tag =
tags.next();
+ if(!tag.isFree) {
+ Logger.error(this, "Tag is
free! "+tag.index);
+ if(tag.bucket == null) {
+ Logger.error(this, "Tag
flagged free yet has no bucket for index "+tag.index);
+ tag.isFree = true;
+ } else continue;
+ }
+ if(tag.bucket != null) {
+ Logger.error(this, "Query
returned tag with valid bucket!");
+ continue;
+ }
+ if(tag.factory !=
PersistentBlobTempBucketFactory.this) continue;
if(notCommittedBlobs.containsKey(tag.index)) continue;
if(freeSlots.containsKey(tag.index))
continue;
if(tag.bucket != null) {
@@ -105,7 +122,7 @@
if(logMINOR) Logger.minor(this, "Adding
slot "+tag.index+" to freeSlots (has a free tag and no taken tag)");
freeSlots.put(tag.index, tag);
added++;
- if(added > 1024) return;
+ if(added > MAX_FREE) return;
}
}
long size;
@@ -138,7 +155,7 @@
added++;
if(logMINOR)
Logger.minor(this,
"Adding slot "+ptr+" to freeSlots, searching for free slots from the end");
- if(added > 1024) return;
+ if(added > MAX_FREE) return;
ptr--;
}
}
@@ -165,12 +182,22 @@
break;
}
}
+ query.constrain(PersistentBlobTempBucketTag.class);
+
query.descend("index").constrain(blocks-1).greater().and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ HashSet<Long> taken = null;
+ ObjectSet<PersistentBlobTempBucketTag> results =
query.execute();
+ while(results.hasNext()) {
+ PersistentBlobTempBucketTag tag =
results.next();
+ if(!tag.isFree) {
+ Logger.error(this, "Block already
exists beyond the end of the file, yet is occupied: block "+tag.index);
+ }
+ if(taken == null) taken = new HashSet<Long>();
+ taken.add(tag.index);
+ }
+
for(int i=0;i<addBlocks;i++) {
ptr = blocks + i;
- query = container.query();
-
query.constrain(PersistentBlobTempBucketTag.class);
-
query.descend("index").constrain(ptr).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
- if(query.execute().hasNext()) continue;
+ if(taken != null && taken.contains(ptr))
continue;
PersistentBlobTempBucketTag tag = new
PersistentBlobTempBucketTag(PersistentBlobTempBucketFactory.this, ptr);
container.store(tag);
synchronized(PersistentBlobTempBucketFactory.this) {
@@ -241,6 +268,7 @@
freeSlots.put(index, tag);
}
tag.bucket = null;
+ tag.isFree = true;
container.store(tag);
container.delete(bucket);
bucket.onRemove();
@@ -257,6 +285,7 @@
throw new IllegalStateException("Slot "+index+" already
occupied!");
}
tag.bucket = bucket;
+ tag.isFree = false;
container.store(tag);
synchronized(this) {
notCommittedBlobs.remove(index);
Modified:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketTag.java
===================================================================
---
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketTag.java
2008-10-31 18:11:45 UTC (rev 23263)
+++
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketTag.java
2008-10-31 18:13:07 UTC (rev 23264)
@@ -5,10 +5,15 @@
final PersistentBlobTempBucketFactory factory;
final long index;
PersistentBlobTempBucket bucket;
+ /** db4o bug: http://tracker.db4o.com/browse/COR-1446
+ * We cannot just query for bucket == null, because it will instantiate
every
+ * object with bucket != null during the query even though we have an
index. */
+ boolean isFree;
PersistentBlobTempBucketTag(PersistentBlobTempBucketFactory f, long
idx) {
factory = f;
index = idx;
+ isFree = true;
}
}