Author: toad
Date: 2008-10-17 22:15:36 +0000 (Fri, 17 Oct 2008)
New Revision: 22997
Added:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobFreeSlotTag.java
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTakenSlotTag.java
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
Modified:
branches/db4o/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
Log:
Store all temp files of exactly 32KB in a single blob file in the temporary
directory. Fall back to one-file-per-bucket if something goes wrong. Hopefully
this will dramatically reduce the number of files in the temp directory and
therefore prevent OOMing on startup enumerating all the persistent temp files
(currently this happens in the UOM code, but we will need to enumerate them for
cleanup soon).
Added:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobFreeSlotTag.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/PersistentBlobFreeSlotTag.java
(rev 0)
+++ branches/db4o/freenet/src/freenet/support/io/PersistentBlobFreeSlotTag.java
2008-10-17 22:15:36 UTC (rev 22997)
@@ -0,0 +1,11 @@
+package freenet.support.io;
+
+public class PersistentBlobFreeSlotTag {
+ final long index;
+ final PersistentBlobTempBucketFactory factory;
+
+ PersistentBlobFreeSlotTag(long index, PersistentBlobTempBucketFactory
factory) {
+ this.index = index;
+ this.factory = factory;
+ }
+}
Added:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTakenSlotTag.java
===================================================================
---
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTakenSlotTag.java
(rev 0)
+++
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTakenSlotTag.java
2008-10-17 22:15:36 UTC (rev 22997)
@@ -0,0 +1,13 @@
+package freenet.support.io;
+
+public class PersistentBlobTakenSlotTag {
+ final long index;
+ final PersistentBlobTempBucketFactory factory;
+ final PersistentBlobTempBucket bucket;
+
+ PersistentBlobTakenSlotTag(long index, PersistentBlobTempBucketFactory
factory, PersistentBlobTempBucket bucket) {
+ this.index = index;
+ this.factory = factory;
+ this.bucket = bucket;
+ }
+}
Added:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
(rev 0)
+++ branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
2008-10-17 22:15:36 UTC (rev 22997)
@@ -0,0 +1,213 @@
+package freenet.support.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+import com.db4o.ObjectContainer;
+
+import freenet.support.api.Bucket;
+
+/**
+ * A persistent temp bucket stored as a blob in a
PersistentBlobTempBucketFactory.
+ * @author Matthew Toseland <toad at amphibian.dyndns.org> (0xE43DA450)
+ */
+public class PersistentBlobTempBucket implements Bucket {
+
+ public final long blockSize;
+ private long size;
+ public final PersistentBlobTempBucketFactory factory;
+ /** The index into the blob file of this specific bucket */
+ final long index;
+ private boolean freed;
+ private boolean readOnly;
+ /** Has this bucket been persisted? If not, it will be only on the
temporary
+ * map in the factory. */
+ private boolean persisted;
+ private final int hashCode;
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public PersistentBlobTempBucket(PersistentBlobTempBucketFactory
factory2, long blockSize2, long slot) {
+ factory = factory2;
+ blockSize = blockSize2;
+ index = slot;
+ hashCode = super.hashCode();
+ }
+
+ public Bucket createShadow() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void free() {
+ factory.freeBucket(index, this); // will call onFree(): always
take the outer lock first.
+ }
+
+ public boolean freed() {
+ return freed;
+ }
+
+ synchronized void onFree() {
+ freed = true;
+ }
+
+ boolean persisted() {
+ return persisted;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ if(freed) throw new IOException("Already freed");
+ final FileChannel channel = factory.channel;
+ return new InputStream() {
+
+ private int offset;
+
+ @Override
+ public int read() throws IOException {
+ byte[] buf = new byte[1];
+ int res = read(buf);
+ if(res == -1) return -1;
+ return buf[0];
+ }
+
+ @Override
+ public int read(byte[] buffer, int bufOffset, int
length) throws IOException {
+ long max;
+ synchronized(PersistentBlobTempBucket.this) {
+ if(freed) throw new IOException("Bucket
freed during read");
+ max = Math.max(blockSize, size);
+ }
+ if(offset < 0) return -1; // throw new
EOFException() ???
+ if(offset + length >= max)
+ length = (int) Math.min(max - offset,
Integer.MAX_VALUE);
+ ByteBuffer buf = ByteBuffer.wrap(buffer,
bufOffset, length);
+ int read = channel.read(buf, blockSize * index
+ offset);
+ if(read > 0) offset += read;
+ return read;
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ return read(buffer, 0, buffer.length);
+ }
+
+ public int available() {
+ return (int) Math.min(blockSize - offset,
Integer.MAX_VALUE);
+ }
+
+ public void close() {
+ // Do nothing.
+ }
+
+ };
+ }
+
+ public String getName() {
+ return factory.getName()+":"+index;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ if(freed) throw new IOException("Already freed");
+ if(readOnly) throw new IOException("Read-only");
+ final FileChannel channel = factory.channel;
+
+ return new OutputStream() {
+
+ private int offset;
+
+ @Override
+ public void write(int arg) throws IOException {
+ byte[] buf = new byte[] { (byte) arg };
+ write(buf, 0, 1);
+ }
+
+ @Override
+ public void write(byte[] buffer, int bufOffset, int
length) throws IOException {
+ synchronized(PersistentBlobTempBucket.this) {
+ if(freed) throw new IOException("Bucket
freed during write");
+ if(readOnly) throw new
IOException("Bucket made read only during write");
+ }
+ long remaining = blockSize - offset;
+ if(remaining <= 0) throw new IOException("Too
big");
+ if(length > remaining) length = (int) remaining;
+ ByteBuffer buf = ByteBuffer.wrap(buffer,
bufOffset, length);
+ int written = 0;
+ while(written < length) {
+ int w = channel.write(buf, blockSize *
index + offset);
+ offset += w;
+
synchronized(PersistentBlobTempBucket.this) {
+ size += w;
+ }
+ written += w;
+ }
+ }
+
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ write(buffer, 0, buffer.length);
+ }
+
+ };
+ }
+
+ public synchronized boolean isReadOnly() {
+ return readOnly;
+ }
+
+ public synchronized void setReadOnly() {
+ readOnly = true;
+ }
+
+ public synchronized long size() {
+ return size;
+ }
+
+ // When created, we take up a slot in the temporary (in-RAM) map on the
factory.
+ // When storeTo() is called the first time, we are committed to a
persistent
+ // structure. When removeFrom() is called afterwards, we are moved back
to the
+ // temporary map, unless we have been freed.
+
+ public void storeTo(ObjectContainer container) {
+ boolean p;
+ // Race conditions with storeTo and removeFrom running on
different threads
+ // in parallel are possible... that sort of behaviour *should*
be very rare,
+ // you should always store it before making it publicly
available...
+ synchronized(this) {
+ p = persisted;
+ }
+ if(!p)
+ factory.store(this, container); // Calls onStore().
Take the outer lock first.
+ }
+
+ public boolean objectCanNew(ObjectContainer container) {
+ synchronized(this) {
+ if(persisted) return true;
+ }
+ storeTo(container);
+ return true;
+ }
+
+ synchronized void onStore() {
+ persisted = true;
+ }
+
+ public void removeFrom(ObjectContainer container) {
+ boolean p;
+ synchronized(this) {
+ p = persisted;
+ }
+ if(p)
+ factory.remove(this, container); // Calls onRemove().
+ container.delete(this);
+ }
+
+ synchronized void onRemove() {
+ persisted = false;
+ }
+
+}
Added:
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
===================================================================
---
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
(rev 0)
+++
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
2008-10-17 22:15:36 UTC (rev 22997)
@@ -0,0 +1,288 @@
+package freenet.support.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeSet;
+
+import com.db4o.ObjectContainer;
+import com.db4o.ObjectSet;
+import com.db4o.query.Query;
+
+import freenet.client.async.ClientContext;
+import freenet.client.async.DBJob;
+import freenet.client.async.DBJobRunner;
+import freenet.support.Logger;
+
+/**
+ * Simple temporary storage mechanism using a single file (or a small number
of
+ * files), and storing buckets of precisely the block size only. Buckets may
not
+ * exceed the block size; the rest of the node should only call us if the
bucket
+ * is of the correct maximum size, and should fall back to one-file-per-bucket
+ * otherwise.
+ *
+ * Currently we only use one blob file. This means that on FAT and some other
+ * filesystems, the node will have to fall back once we reach 2GB of temp
files.
+ * @author Matthew Toseland <toad at amphibian.dyndns.org> (0xE43DA450)
+ */
+public class PersistentBlobTempBucketFactory {
+
+ public final long blockSize;
+ private File storageFile;
+ private transient RandomAccessFile raf;
+ /** We use NIO for the equivalent of pwrite/pread. This is parallelized
on unix
+ * but sadly not on Windows. */
+ transient FileChannel channel;
+
+ /** Blobs in memory only: in the database there will still be a "free"
tag */
+ private transient Map<Long,PersistentBlobTempBucket> notCommittedBlobs;
+
+ /** Non-exhaustive list of free slots. If we run out we need to query
for
+ * more. */
+ private transient TreeSet<Long> freeSlots;
+
+ private transient DBJobRunner jobRunner;
+
+ private transient Random weakRandomSource;
+
+ private final long nodeDBHandle;
+
+ public PersistentBlobTempBucketFactory(long blockSize2, long
nodeDBHandle2, File storageFile2) {
+ blockSize = blockSize2;
+ nodeDBHandle = nodeDBHandle2;
+ storageFile = storageFile2;
+ }
+
+ void onInit(ObjectContainer container, DBJobRunner jobRunner2, Random
fastWeakRandom, File storageFile2, long blockSize2) throws IOException {
+ container.activate(storageFile, 100);
+ if(storageFile2.getPath().equals(storageFile.getPath())) {
+ if(blockSize != blockSize2)
+ throw new IllegalStateException("My block size
is "+blockSize2+
+ " but stored block size is
"+blockSize+
+ " for same file "+storageFile);
+ } else {
+ if(!FileUtil.moveTo(storageFile, storageFile2, false))
+ throw new IOException("Unable to move temp blob
file from "+storageFile+" to "+storageFile2);
+ }
+ raf = new RandomAccessFile(storageFile, "rw");
+ channel = raf.getChannel();
+ notCommittedBlobs = new
HashMap<Long,PersistentBlobTempBucket>();
+ freeSlots = new TreeSet<Long>();
+ jobRunner = jobRunner2;
+ weakRandomSource = fastWeakRandom;
+ }
+
+ public String getName() {
+ return storageFile.getPath();
+ }
+
+ 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;
+ }
+ Query query = container.query();
+
query.constrain(PersistentBlobFreeSlotTag.class).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ ObjectSet<PersistentBlobFreeSlotTag> tags =
query.execute();
+ Long[] notCommitted;
+ int added = 0;
+ synchronized(PersistentBlobTempBucketFactory.this) {
+ while(tags.hasNext()) {
+ PersistentBlobFreeSlotTag tag =
tags.next();
+ if(notCommittedBlobs.get(tag.index) !=
null) continue;
+ if(freeSlots.contains(tag.index))
continue;
+ Query check = container.query();
+
check.constrain(PersistentBlobTakenSlotTag.class);
+
check.descend("index").constrain(tag.index).and(check.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ ObjectSet<PersistentBlobTakenSlotTag>
checkResults = check.execute();
+ if(checkResults.hasNext()) {
+ Logger.error(this, "slot
"+tag.index+" is already taken by "+checkResults.next().bucket+", but also has
a FreeSlotTag! total matches: "+(checkResults.size()+1));
+ container.delete(tag);
+ continue;
+ }
+ if(logMINOR) Logger.minor(this, "Adding
slot "+tag.index+" to freeSlots (has a free tag and no taken tag)");
+ freeSlots.add(tag.index);
+ added++;
+ if(added > 1024) return;
+ }
+ }
+ long size;
+ try {
+ size = channel.size();
+ } catch (IOException e1) {
+ Logger.error(this, "Unable to find size of temp
blob storage file: "+e1, e1);
+ return;
+ }
+ size -= size % blockSize;
+ long blocks = size / blockSize;
+ long ptr = blocks - 1;
+ query = container.query();
+ query.constrain(PersistentBlobTakenSlotTag.class);
+
query.descend("index").constrain(ptr).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ // Try from the end, until we find no more.
+ while(ptr > 0 && !query.execute().hasNext()) {
+ boolean stored = false;
+
synchronized(PersistentBlobTempBucketFactory.this) {
+ stored = notCommittedBlobs.get(ptr) ==
null;
+ if(stored) {
+ if(freeSlots.contains(ptr))
break;
+ freeSlots.add(ptr);
+ }
+ }
+ query = container.query();
+
query.constrain(PersistentBlobFreeSlotTag.class);
+
query.descend("index").constrain(ptr).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ if(query.execute().hasNext()) break;
+ if(stored) {
+ container.store(new
PersistentBlobFreeSlotTag(ptr, PersistentBlobTempBucketFactory.this));
+ added++;
+ }
+ if(logMINOR)
+ Logger.minor(this, "Adding slot "+ptr+"
to freeSlots, searching for free slots from the end");
+ if(added > 1024) return;
+ ptr--;
+ query = container.query();
+
query.constrain(PersistentBlobTakenSlotTag.class);
+
query.descend("index").constrain(ptr).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ }
+ // We haven't done an exhaustive search for freeable
slots, slots
+ // with no tag at all etc. This happens on startup.
+ // Lets extend the file.
+ // FIXME if physical security is LOW, just set the
length, possibly
+ // padding will nonrandom nulls on unix.
+ long extendBy = blockSize * 32;
+ long written = 0;
+ byte[] buf = new byte[4096];
+ ByteBuffer buffer = ByteBuffer.wrap(buf);
+ while(written < extendBy) {
+ weakRandomSource.nextBytes(buf);
+ int bytesLeft = (int) Math.min(extendBy -
written, Integer.MAX_VALUE);
+ if(bytesLeft < buf.length)
+ buffer.limit(bytesLeft);
+ try {
+ written += channel.write(buffer, size +
written);
+ buffer.clear();
+ } catch (IOException e) {
+ break;
+ }
+ }
+ for(int i=0;i<written / blockSize;i++) {
+ ptr = blocks + i;
+ container.store(new
PersistentBlobFreeSlotTag(ptr, PersistentBlobTempBucketFactory.this));
+
synchronized(PersistentBlobTempBucketFactory.this) {
+ freeSlots.add(ptr);
+ if(logMINOR)
+ Logger.minor(this, "Adding slot
"+ptr+" to freeSlots while extending storage file");
+ }
+ }
+ }
+
+ };
+
+ /**
+ * @return A bucket, or null in various failure cases.
+ */
+ public PersistentBlobTempBucket makeBucket() {
+ // Find a free slot.
+ long slotNo;
+ synchronized(this) {
+ if(!freeSlots.isEmpty()) {
+ Long slot = freeSlots.first();
+ freeSlots.remove(slot);
+ if(notCommittedBlobs.get(slot) != null) {
+ Logger.error(this, "Slot "+slot+"
already occupied despite being in freeSlots!!");
+ return null;
+ }
+ PersistentBlobTempBucket bucket = new
PersistentBlobTempBucket(this, blockSize, slot);
+ notCommittedBlobs.put(slot, bucket);
+ if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Using slot "+slot+" for "+bucket);
+ return bucket;
+ }
+ }
+ jobRunner.runBlocking(slotFinder, NativeThread.HIGH_PRIORITY);
+ synchronized(this) {
+ if(!freeSlots.isEmpty()) {
+ Long slot = freeSlots.first();
+ freeSlots.remove(slot);
+ if(notCommittedBlobs.get(slot) != null) {
+ Logger.error(this, "Slot "+slot+"
already occupied despite being in freeSlots!!");
+ return null;
+ }
+ PersistentBlobTempBucket bucket = new
PersistentBlobTempBucket(this, blockSize, slot);
+ notCommittedBlobs.put(slot, bucket);
+ if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Using slot "+slot+" for "+bucket+" (2)");
+ return bucket;
+ }
+ }
+ Logger.error(this, "Returning null, unable to create a bucket
for some reason, node will fallback to file-based buckets");
+ return null;
+ }
+
+ public synchronized void freeBucket(long index,
PersistentBlobTempBucket bucket) {
+ notCommittedBlobs.remove(index);
+ bucket.onFree();
+ }
+
+ public synchronized void remove(PersistentBlobTempBucket bucket,
ObjectContainer container) {
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Removing bucket "+bucket+" for slot
"+bucket.index+" from database");
+ if(!bucket.persisted()) return;
+ Query query = container.query();
+ long index = bucket.index;
+ freeSlots.add(index);
+ query.constrain(PersistentBlobTakenSlotTag.class);
+
query.descend("index").constrain(index).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ ObjectSet<PersistentBlobTakenSlotTag> tags = query.execute();
+ while(tags.hasNext()) {
+ PersistentBlobTakenSlotTag tag = tags.next();
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Deleting taken slot tag for
index "+index+" : "+tag+" : "+tag.index);
+ container.delete(tag);
+ }
+ query = container.query();
+
query.constrain(PersistentBlobFreeSlotTag.class).and(query.descend("index").constrain(index).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this)));
+ if(!query.execute().hasNext()) {
+ PersistentBlobFreeSlotTag tag = new
PersistentBlobFreeSlotTag(index, this);
+ container.store(tag);
+ }
+ bucket.onRemove();
+ }
+
+ public void store(PersistentBlobTempBucket bucket, ObjectContainer
container) {
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Storing bucket "+bucket+" for slot
"+bucket.index+" to database");
+ long index = bucket.index;
+ // FIXME paranoid check, remove
+ Query query = container.query();
+ query.constrain(PersistentBlobTakenSlotTag.class);
+
query.descend("index").constrain(index).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ ObjectSet<PersistentBlobTakenSlotTag> taken = query.execute();
+ if(taken.hasNext()) {
+ PersistentBlobTakenSlotTag tag = taken.next();
+ Logger.error(this, "Slot "+index+" already occupied!:
"+tag.bucket+" for "+tag.index);
+ throw new IllegalStateException("Slot "+index+" already
occupied!");
+ }
+ // Now the normal bit
+ query = container.query();
+ query.constrain(PersistentBlobFreeSlotTag.class);
+
query.descend("index").constrain(index).and(query.descend("factory").constrain(PersistentBlobTempBucketFactory.this));
+ ObjectSet<PersistentBlobFreeSlotTag> results = query.execute();
+ while(results.hasNext()) {
+ PersistentBlobFreeSlotTag tag = results.next();
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Deleting free slot tag for
index "+index+" : "+tag+" : "+tag.index);
+ container.delete(tag);
+ }
+ bucket.onStore();
+ PersistentBlobTakenSlotTag tag = new
PersistentBlobTakenSlotTag(index, this, bucket);
+ container.store(tag);
+ }
+
+}
Modified:
branches/db4o/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
===================================================================
---
branches/db4o/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2008-10-17 22:09:23 UTC (rev 22996)
+++
branches/db4o/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2008-10-17 22:15:36 UTC (rev 22997)
@@ -14,7 +14,9 @@
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;
+import freenet.client.async.DBJobRunner;
import freenet.crypt.RandomSource;
+import freenet.keys.CHKBlock;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
@@ -46,9 +48,14 @@
private final long nodeDBHandle;
private volatile boolean encrypt;
+
+ private final PersistentBlobTempBucketFactory blobFactory;
+
+ static final int BLOB_SIZE = CHKBlock.DATA_LENGTH;
public PersistentTempBucketFactory(File dir, final String prefix,
RandomSource strongPRNG, Random weakPRNG, boolean encrypt, long nodeDBHandle)
throws IOException {
boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
+ blobFactory = new PersistentBlobTempBucketFactory(BLOB_SIZE,
nodeDBHandle, new File(dir, "persistent-blob.tmp"));
this.strongPRNG = strongPRNG;
this.nodeDBHandle = nodeDBHandle;
this.weakPRNG = weakPRNG;
@@ -121,7 +128,12 @@
}
public Bucket makeBucket(long size) throws IOException {
- PersistentTempFileBucket rawBucket = new
PersistentTempFileBucket(fg.makeRandomFilename(), fg);
+ Bucket rawBucket = null;
+ if(size == BLOB_SIZE) {
+ rawBucket = blobFactory.makeBucket();
+ }
+ if(rawBucket == null)
+ rawBucket = new
PersistentTempFileBucket(fg.makeRandomFilename(), fg);
Bucket maybeEncryptedBucket = (encrypt ? new
PaddedEphemerallyEncryptedBucket(rawBucket, 1024, strongPRNG, weakPRNG) :
rawBucket);
return new DelayedFreeBucket(this, maybeEncryptedBucket);
}
@@ -163,7 +175,7 @@
return encrypt;
}
- public static PersistentTempBucketFactory load(File dir, String prefix,
RandomSource random, Random fastWeakRandom, ObjectContainer container, final
long nodeDBHandle, boolean encrypt) throws IOException {
+ public static PersistentTempBucketFactory load(File dir, String prefix,
RandomSource random, Random fastWeakRandom, ObjectContainer container, final
long nodeDBHandle, boolean encrypt, DBJobRunner jobRunner) throws IOException {
ObjectSet<PersistentTempBucketFactory> results =
container.query(new Predicate<PersistentTempBucketFactory>() {
public boolean match(PersistentTempBucketFactory
factory) {
if(factory.nodeDBHandle == nodeDBHandle) return
true;
@@ -175,9 +187,14 @@
container.activate(factory, 5);
factory.init(dir, prefix, random, fastWeakRandom);
factory.setEncryption(encrypt);
+ factory.blobFactory.onInit(container, jobRunner,
fastWeakRandom, new File(dir, "persistent-blob.tmp"), BLOB_SIZE);
return factory;
- } else
- return new PersistentTempBucketFactory(dir, prefix,
random, fastWeakRandom, encrypt, nodeDBHandle);
+ } else {
+ PersistentTempBucketFactory factory =
+ new PersistentTempBucketFactory(dir, prefix,
random, fastWeakRandom, encrypt, nodeDBHandle);
+ factory.blobFactory.onInit(container, jobRunner,
fastWeakRandom, new File(dir, "persistent-blob.tmp"), BLOB_SIZE);
+ return factory;
+ }
}
public void setEncryption(boolean encrypt) {