Author: toad
Date: 2008-07-04 14:28:59 +0000 (Fri, 04 Jul 2008)
New Revision: 20993
Added:
branches/db4o/freenet/src/freenet/client/async/PendingKeyItem.java
Modified:
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerBase.java
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerNonPersistent.java
branches/db4o/freenet/src/freenet/node/Node.java
Log:
Implement pendingKeys differently for transient vs persistent.
For transient, keep the existing Map-based code.
For persistent, use PendingKeyItem's and queries.
Hopefully this is a speedup.
Modified:
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerBase.java
===================================================================
---
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerBase.java
2008-07-04 13:58:46 UTC (rev 20992)
+++
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerBase.java
2008-07-04 14:28:59 UTC (rev 20993)
@@ -41,11 +41,6 @@
final boolean isInsertScheduler;
final boolean isSSKScheduler;
- /** All pending gets by key. Used to automatically satisfy pending
requests when either the key is fetched by
- * an overlapping request, or it is fetched by a request from another
node. Operations on this are synchronized on
- * itself. */
- protected final Map /* <Key, SendableGet[]> */ pendingKeys;
-
/**
* Structure:
* array (by priority) -> // one element per possible priority
@@ -60,202 +55,15 @@
abstract boolean persistent();
- protected ClientRequestSchedulerBase(boolean forInserts, boolean
forSSKs, Map pendingKeys, Map allRequestsByClientRequest, List recentSuccesses)
{
+ protected ClientRequestSchedulerBase(boolean forInserts, boolean
forSSKs, Map allRequestsByClientRequest, List recentSuccesses) {
this.isInsertScheduler = forInserts;
this.isSSKScheduler = forSSKs;
- this.pendingKeys = pendingKeys;
this.allRequestsByClientRequest = allRequestsByClientRequest;
this.recentSuccesses = recentSuccesses;
priorities = new
SortedVectorByNumber[RequestStarter.NUMBER_OF_PRIORITY_CLASSES];
logMINOR = Logger.shouldLog(Logger.MINOR,
ClientRequestSchedulerBase.class);
}
- /**
- * Register a pending key to an already-registered request. This is
necessary if we've
- * already registered a SendableGet, but we later add some more keys to
it.
- */
- void addPendingKey(Key nodeKey, SendableGet getter, ObjectContainer
container) {
- logMINOR = Logger.shouldLog(Logger.MINOR,
ClientRequestSchedulerBase.class);
- if(logMINOR)
- Logger.minor(this, "Adding pending key "+nodeKey+" for
"+getter);
- synchronized(pendingKeys) {
- Object o = pendingKeys.get(nodeKey);
- if(o == null) {
- pendingKeys.put(nodeKey, getter);
- } else if(o instanceof SendableGet) {
- SendableGet oldGet = (SendableGet) o;
- if(oldGet != getter) {
- pendingKeys.put(nodeKey, new
SendableGet[] { oldGet, getter });
- }
- } else {
- SendableGet[] gets = (SendableGet[]) o;
- boolean found = false;
- for(int j=0;j<gets.length;j++) {
- if(gets[j] == getter) {
- found = true;
- break;
- }
- }
- if(!found) {
- SendableGet[] newGets = new
SendableGet[gets.length+1];
- System.arraycopy(gets, 0, newGets, 0,
gets.length);
- newGets[gets.length] = getter;
- pendingKeys.put(nodeKey, newGets);
- }
- }
- }
- }
-
- public boolean removePendingKey(SendableGet getter, boolean complain,
Key key, ObjectContainer container) {
- if(logMINOR)
- Logger.minor(this, "Removing pending key: "+getter+"
for "+key);
- boolean dropped = false;
- Object o;
- /*
- * Because arrays are not basic types,
pendingKeys.activationDepth(1) means that
- * the SendableGet's returned here will be activated to depth
1, even if they were
- * within a SendableGet[]. Tested as of 21/05/08.
- */
- synchronized(pendingKeys) {
- o = pendingKeys.get(key);
- if(o == null) {
- if(complain)
- Logger.normal(this, "Not found:
"+getter+" for "+key+" removing (no such key)");
- } else if(o instanceof SendableGet) {
- SendableGet oldGet = (SendableGet) o;
- if(oldGet != getter) {
- if(complain)
- Logger.normal(this, "Not found:
"+getter+" for "+key+" removing (1 getter)");
- } else {
- dropped = true;
- pendingKeys.remove(key);
- if(logMINOR)
- Logger.minor(this, "Removed
only getter (1) for "+key, new Exception("debug"));
- }
- } else {
- SendableGet[] gets = (SendableGet[]) o;
- final int getsLength = gets.length;
- SendableGet[] newGets = new
SendableGet[getsLength > 1 ? getsLength-1 : 0];
- boolean found = false;
- int x = 0;
- for(int j=0;j<getsLength;j++) {
- if(gets[j] == getter) {
- found = true;
- dropped = true;
- continue;
- }
- if(x == newGets.length) {
- if(!found) {
- if(complain)
-
Logger.normal(this, "Not found: "+getter+" for "+key+" removing ("+getsLength+"
getters)");
- return false; // not
here
- }
- }
- if(gets[j] == null) continue;
- if(gets[j].isCancelled(container))
continue;
- newGets[x++] = gets[j];
- }
- if(x == 0) {
- pendingKeys.remove(key);
- if(logMINOR)
- Logger.minor(this, "Removed
only getter (2) for "+key, new Exception("debug"));
- } else if(x == 1) {
- pendingKeys.put(key, newGets[0]);
- } else {
- if(x != getsLength-1) {
- SendableGet[] newNewGets = new
SendableGet[x];
- System.arraycopy(newGets, 0,
newNewGets, 0, x);
- newGets = newNewGets;
- }
- pendingKeys.put(key, newGets);
- }
- }
- }
- return dropped;
- }
-
- public SendableGet[] removePendingKey(Key key, ObjectContainer
container) {
- Object o;
- final SendableGet[] gets;
- synchronized(pendingKeys) {
- o = pendingKeys.remove(key);
- }
- if(o == null) return null;
- if(o instanceof SendableGet) {
- gets = new SendableGet[] { (SendableGet) o };
- if(logMINOR)
- Logger.minor(this, "Removing all pending keys
for "+key+" (1)", new Exception("debug"));
- } else {
- gets = (SendableGet[]) o;
- if(logMINOR)
- Logger.minor(this, "Removing all pending keys
for "+key+" ("+gets.length+")", new Exception("debug"));
- }
- return gets;
- }
-
- public boolean anyWantKey(Key key, ObjectContainer container) {
- synchronized(pendingKeys) {
- return pendingKeys.get(key) != null;
- }
- }
-
- public short getKeyPrio(Key key, short priority, ObjectContainer
container) {
- synchronized(pendingKeys) {
- Object o = pendingKeys.get(key);
- if(o == null) {
- // Blah
- } else if(o instanceof SendableGet) {
- short p =
((SendableGet)o).getPriorityClass(container);
- if(p < priority) priority = p;
- } else { // if(o instanceof SendableGet[]) {
- SendableGet[] gets = (SendableGet[]) o;
- for(int i=0;i<gets.length;i++) {
- short p =
gets[i].getPriorityClass(container);
- if(p < priority) priority = p;
- }
- }
- }
- return priority;
- }
-
- public SendableGet[] getClientsForPendingKey(Key key, ObjectContainer
container) {
- Object o;
- synchronized(pendingKeys) {
- o = pendingKeys.get(key);
- }
- if(o == null) {
- return null;
- } else if(o instanceof SendableGet) {
- SendableGet get = (SendableGet) o;
- return new SendableGet[] { get };
- } else {
- return (SendableGet[]) o;
- }
- }
-
- protected boolean inPendingKeys(SendableRequest req, Key key,
ObjectContainer container) {
- Object o;
- synchronized(pendingKeys) {
- o = pendingKeys.get(key);
- }
- if(o == null) {
- return false;
- } else if(o instanceof SendableGet) {
- return o == req;
- } else {
- SendableGet[] gets = (SendableGet[]) o;
- for(int i=0;i<gets.length;i++)
- if(gets[i] == req) return true;
- }
- return false;
- }
-
- public long countQueuedRequests(ObjectContainer container) {
- if(pendingKeys != null)
- return pendingKeys.size();
- else return 0;
- }
-
void innerRegister(SendableRequest req, RandomSource random,
ObjectContainer container) {
if(req.persistent() != persistent())
throw new IllegalArgumentException("innerRegister for
persistence="+req.persistent()+" but our persistence is "+persistent());
@@ -280,8 +88,6 @@
if(logMINOR) Logger.minor(this, "Registered "+req+" on
prioclass="+prio+", retrycount="+retryCount+" v.size()="+v.size());
}
- protected abstract Set
makeSetForAllRequestsByClientRequest(ObjectContainer container);
-
void addToGrabArray(short priorityClass, int retryCount, int rc, Object
client, ClientRequester cr, SendableRequest req, RandomSource random,
ObjectContainer container) {
if((priorityClass > RequestStarter.MINIMUM_PRIORITY_CLASS) ||
(priorityClass < RequestStarter.MAXIMUM_PRIORITY_CLASS))
throw new IllegalStateException("Invalid priority:
"+priorityClass+" - range is "+RequestStarter.MAXIMUM_PRIORITY_CLASS+" (most
important) to "+RequestStarter.MINIMUM_PRIORITY_CLASS+" (least important)");
@@ -395,5 +201,35 @@
}
}
}
+
+ public short getKeyPrio(Key key, short priority, ObjectContainer
container) {
+ SendableGet[] getters = getClientsForPendingKey(key, container);
+ if(getters == null) return priority;
+ for(int i=0;i<getters.length;i++) {
+ if(persistent())
+ container.activate(getters[i], 1);
+ short prio = getters[i].getPriorityClass(container);
+ if(prio < priority) priority = prio;
+ if(persistent())
+ container.deactivate(getters[i], 1);
+ }
+ return priority;
+ }
+
+ public abstract long countQueuedRequests(ObjectContainer container);
+
+ protected abstract boolean inPendingKeys(SendableGet req, Key key,
ObjectContainer container);
+
+ public abstract SendableGet[] getClientsForPendingKey(Key key,
ObjectContainer container);
+
+ public abstract boolean anyWantKey(Key key, ObjectContainer container);
+
+ public abstract SendableGet[] removePendingKey(Key key, ObjectContainer
container);
+
+ public abstract boolean removePendingKey(SendableGet getter, boolean
complain, Key key, ObjectContainer container);
+
+ abstract void addPendingKey(Key key, SendableGet getter,
ObjectContainer container);
+
+ protected abstract Set
makeSetForAllRequestsByClientRequest(ObjectContainer container);
}
Modified:
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
===================================================================
---
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
2008-07-04 13:58:46 UTC (rev 20992)
+++
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
2008-07-04 14:28:59 UTC (rev 20993)
@@ -11,6 +11,7 @@
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;
+import com.db4o.query.Query;
import com.db4o.types.Db4oList;
import com.db4o.types.Db4oMap;
@@ -92,7 +93,7 @@
}
ClientRequestSchedulerCore(Node node, boolean forInserts, boolean
forSSKs, ObjectContainer selectorContainer, long cooldownTime) {
- super(forInserts, forSSKs, forInserts ? null :
selectorContainer.ext().collections().newHashMap(1024),
selectorContainer.ext().collections().newHashMap(32),
selectorContainer.ext().collections().newLinkedList());
+ super(forInserts, forSSKs,
selectorContainer.ext().collections().newHashMap(32),
selectorContainer.ext().collections().newLinkedList());
this.nodeDBHandle = node.nodeDBHandle;
if(!forInserts) {
this.persistentCooldownQueue = new
PersistentCooldownQueue();
@@ -103,14 +104,10 @@
private void onStarted(ObjectContainer container, long cooldownTime,
ClientRequestScheduler sched, ClientContext context) {
System.err.println("insert scheduler: "+isInsertScheduler);
- if(pendingKeys == null)
- System.err.println("pendingKeys is null");
if(allRequestsByClientRequest == null)
System.err.println("allRequestsByClientRequest is
null");
if(recentSuccesses == null)
System.err.println("recentSuccesses is null");
- if(!isInsertScheduler)
- ((Db4oMap)pendingKeys).activationDepth(1);
((Db4oMap)allRequestsByClientRequest).activationDepth(1);
((Db4oList)recentSuccesses).activationDepth(1);
if(!isInsertScheduler) {
@@ -191,6 +188,8 @@
container.delete(req);
continue;
}
+ if(logMINOR)
+ Logger.minor(this, "Adding old request: "+req);
sched.addToStarterQueue(req);
}
// if(count > ClientRequestScheduler.MAX_STARTER_QUEUE_SIZE)
@@ -276,7 +275,7 @@
Logger.minor(this, "Storing "+ret+" for
"+req);
if((ctr++ & 15) == 0) {
// This check is quite expensive, don't
do it all the time.
- if((req instanceof SendableGet) &&
!inPendingKeys(req, key, container)) {
+ if((req instanceof SendableGet) &&
!inPendingKeys((SendableGet)req, key, container)) {
Logger.error(this, "Selected
key not in pendingKeys: key "+key+" for "+req);
}
}
@@ -286,7 +285,7 @@
return ret;
}
}
-
+
SendableRequest removeFirstInner(int fuzz, RandomSource random,
OfferedKeysList[] offeredKeys, RequestStarter starter,
ClientRequestSchedulerNonPersistent schedTransient, boolean transientOnly,
boolean notTransient, short maxPrio, int retryCount, ClientContext context,
ObjectContainer container) {
// Priorities start at 0
if(logMINOR) Logger.minor(this, "removeFirst()");
@@ -609,5 +608,148 @@
return new Db4oSet(container, 1);
}
+ public long countQueuedRequests(ObjectContainer container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(item.nodeDBHandle == nodeDBHandle) return
true;
+ return false;
+ }
+ });
+ return pending.size();
+ }
+
+ protected boolean inPendingKeys(SendableGet req, final Key key,
ObjectContainer container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ if(pending.hasNext()) {
+ PendingKeyItem item = (PendingKeyItem) pending.next();
+ return item.hasGetter(req);
+ }
+ Logger.error(this, "Key not in pendingKeys at all");
+// Key copy = key.cloneKey();
+// addPendingKey(copy, req, container);
+// container.commit();
+// pending = container.query(new Predicate() {
+// public boolean match(PendingKeyItem item) {
+// if(!key.equals(item.key)) return false;
+// if(item.nodeDBHandle != nodeDBHandle) return
false;
+// return true;
+// }
+// });
+// if(!pending.hasNext()) {
+// Logger.error(this, "INDEXES BROKEN!!!");
+// } else {
+// PendingKeyItem item = (PendingKeyItem) (pending.next());
+// Key k = item.key;
+// container.delete(item);
+// Logger.error(this, "Indexes work");
+// }
+ return false;
+ }
+
+ public SendableGet[] getClientsForPendingKey(final Key key,
ObjectContainer container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ if(pending.hasNext()) {
+ PendingKeyItem item = (PendingKeyItem) pending.next();
+ return item.getters();
+ }
+ return null;
+ }
+
+ public boolean anyWantKey(final Key key, ObjectContainer container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ return pending.hasNext();
+ }
+
+ public SendableGet[] removePendingKey(final Key key, ObjectContainer
container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ if(pending.hasNext()) {
+ PendingKeyItem item = (PendingKeyItem) pending.next();
+ SendableGet[] getters = item.getters();
+ container.delete(item);
+ return getters;
+ }
+ return null;
+ }
+
+ public boolean removePendingKey(SendableGet getter, boolean complain,
final Key key, ObjectContainer container) {
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ if(pending.hasNext()) {
+ PendingKeyItem item = (PendingKeyItem) pending.next();
+ boolean ret = item.removeGetter(getter);
+ if(item.isEmpty()) {
+ container.delete(item);
+ } else {
+ container.set(item);
+ }
+ return ret;
+ }
+ return false;
+ }
+
+ protected void addPendingKey(final Key key, SendableGet getter,
ObjectContainer container) {
+ if(logMINOR)
+ Logger.minor(this, "Adding pending key for "+key+" for
"+getter);
+ long startTime = System.currentTimeMillis();
+// Query query = container.query();
+// query.constrain(PendingKeyItem.class);
+// query.descend("key").constrain(key);
+// query.descend("nodeDBHandle").constrain(new Long(nodeDBHandle));
+// ObjectSet pending = query.execute();
+
+ // Native version seems to be faster, at least for a few
thousand items...
+ // I'm not sure whether it's using the index though, we may
need to reconsider for larger queues... FIXME
+
+ ObjectSet pending = container.query(new Predicate() {
+ public boolean match(PendingKeyItem item) {
+ if(!key.equals(item.key)) return false;
+ if(item.nodeDBHandle != nodeDBHandle) return
false;
+ return true;
+ }
+ });
+ long endTime = System.currentTimeMillis();
+ if(endTime - startTime > 1000)
+ Logger.error(this, "Query took "+(endTime -
startTime)+"ms");
+ else if(logMINOR)
+ Logger.minor(this, "Query took "+(endTime -
startTime)+"ms");
+ if(pending.hasNext()) {
+ PendingKeyItem item = (PendingKeyItem) pending.next();
+ item.addGetter(getter);
+ container.set(item);
+ } else {
+ PendingKeyItem item = new PendingKeyItem(key, getter,
nodeDBHandle);
+ container.set(item);
+ }
+ }
+
}
Modified:
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerNonPersistent.java
===================================================================
---
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerNonPersistent.java
2008-07-04 13:58:46 UTC (rev 20992)
+++
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerNonPersistent.java
2008-07-04 14:28:59 UTC (rev 20993)
@@ -6,16 +6,23 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.Map;
import java.util.Set;
import com.db4o.ObjectContainer;
+import freenet.keys.Key;
+import freenet.node.SendableGet;
+import freenet.node.SendableRequest;
+import freenet.support.Logger;
+
/**
* Parallel scheduler structures for non-persistent requests.
* @author toad
*/
class ClientRequestSchedulerNonPersistent extends ClientRequestSchedulerBase {
+ private boolean logMINOR;
/**
* Structure:
* array (by priority) -> // one element per possible priority
@@ -26,9 +33,19 @@
*/
final LinkedList /* <BaseSendableGet> */ recentSuccesses;
+ /** All pending gets by key. Used to automatically satisfy pending
requests when either the key is fetched by
+ * an overlapping request, or it is fetched by a request from another
node. Operations on this are synchronized on
+ * itself. */
+ protected final Map /* <Key, SendableGet[]> */ pendingKeys;
+
ClientRequestSchedulerNonPersistent(ClientRequestScheduler sched) {
- super(sched.isInsertScheduler, sched.isSSKScheduler,
sched.isInsertScheduler ? null : new HashMap(), new HashMap(), new
LinkedList());
+ super(sched.isInsertScheduler, sched.isSSKScheduler, new
HashMap(), new LinkedList());
recentSuccesses = new LinkedList();
+ if(sched.isInsertScheduler)
+ pendingKeys = null;
+ else
+ pendingKeys = new HashMap();
+ logMINOR = Logger.shouldLog(Logger.MINOR, this);
}
boolean persistent() {
@@ -42,5 +59,192 @@
protected Set makeSetForAllRequestsByClientRequest(ObjectContainer
ignored) {
return new HashSet();
}
+
+ /**
+ * Register a pending key to an already-registered request. This is
necessary if we've
+ * already registered a SendableGet, but we later add some more keys to
it.
+ */
+ void addPendingKey(Key nodeKey, SendableGet getter, ObjectContainer
container) {
+ logMINOR = Logger.shouldLog(Logger.MINOR,
ClientRequestSchedulerBase.class);
+ if(logMINOR)
+ Logger.minor(this, "Adding pending key "+nodeKey+" for
"+getter);
+ synchronized(pendingKeys) {
+ Object o = pendingKeys.get(nodeKey);
+ if(o == null) {
+ pendingKeys.put(nodeKey, getter);
+ } else if(o instanceof SendableGet) {
+ SendableGet oldGet = (SendableGet) o;
+ if(oldGet != getter) {
+ pendingKeys.put(nodeKey, new
SendableGet[] { oldGet, getter });
+ }
+ } else {
+ SendableGet[] gets = (SendableGet[]) o;
+ boolean found = false;
+ for(int j=0;j<gets.length;j++) {
+ if(gets[j] == getter) {
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ SendableGet[] newGets = new
SendableGet[gets.length+1];
+ System.arraycopy(gets, 0, newGets, 0,
gets.length);
+ newGets[gets.length] = getter;
+ pendingKeys.put(nodeKey, newGets);
+ }
+ }
+ }
+ }
+ public boolean removePendingKey(SendableGet getter, boolean complain,
Key key, ObjectContainer container) {
+ if(logMINOR)
+ Logger.minor(this, "Removing pending key: "+getter+"
for "+key);
+ boolean dropped = false;
+ Object o;
+ /*
+ * Because arrays are not basic types,
pendingKeys.activationDepth(1) means that
+ * the SendableGet's returned here will be activated to depth
1, even if they were
+ * within a SendableGet[]. Tested as of 21/05/08.
+ */
+ synchronized(pendingKeys) {
+ o = pendingKeys.get(key);
+ if(o == null) {
+ if(complain)
+ Logger.normal(this, "Not found:
"+getter+" for "+key+" removing (no such key)");
+ } else if(o instanceof SendableGet) {
+ SendableGet oldGet = (SendableGet) o;
+ if(oldGet != getter) {
+ if(complain)
+ Logger.normal(this, "Not found:
"+getter+" for "+key+" removing (1 getter)");
+ } else {
+ dropped = true;
+ pendingKeys.remove(key);
+ if(logMINOR)
+ Logger.minor(this, "Removed
only getter (1) for "+key, new Exception("debug"));
+ }
+ } else {
+ SendableGet[] gets = (SendableGet[]) o;
+ final int getsLength = gets.length;
+ SendableGet[] newGets = new
SendableGet[getsLength > 1 ? getsLength-1 : 0];
+ boolean found = false;
+ int x = 0;
+ for(int j=0;j<getsLength;j++) {
+ if(gets[j] == getter) {
+ found = true;
+ dropped = true;
+ continue;
+ }
+ if(x == newGets.length) {
+ if(!found) {
+ if(complain)
+
Logger.normal(this, "Not found: "+getter+" for "+key+" removing ("+getsLength+"
getters)");
+ return false; // not
here
+ }
+ }
+ if(gets[j] == null) continue;
+ if(gets[j].isCancelled(container))
continue;
+ newGets[x++] = gets[j];
+ }
+ if(x == 0) {
+ pendingKeys.remove(key);
+ if(logMINOR)
+ Logger.minor(this, "Removed
only getter (2) for "+key, new Exception("debug"));
+ } else if(x == 1) {
+ pendingKeys.put(key, newGets[0]);
+ } else {
+ if(x != getsLength-1) {
+ SendableGet[] newNewGets = new
SendableGet[x];
+ System.arraycopy(newGets, 0,
newNewGets, 0, x);
+ newGets = newNewGets;
+ }
+ pendingKeys.put(key, newGets);
+ }
+ }
+ }
+ return dropped;
+ }
+
+ public SendableGet[] removePendingKey(Key key, ObjectContainer
container) {
+ Object o;
+ final SendableGet[] gets;
+ synchronized(pendingKeys) {
+ o = pendingKeys.remove(key);
+ }
+ if(o == null) return null;
+ if(o instanceof SendableGet) {
+ gets = new SendableGet[] { (SendableGet) o };
+ if(logMINOR)
+ Logger.minor(this, "Removing all pending keys
for "+key+" (1)", new Exception("debug"));
+ } else {
+ gets = (SendableGet[]) o;
+ if(logMINOR)
+ Logger.minor(this, "Removing all pending keys
for "+key+" ("+gets.length+")", new Exception("debug"));
+ }
+ return gets;
+ }
+
+ public boolean anyWantKey(Key key, ObjectContainer container) {
+ synchronized(pendingKeys) {
+ return pendingKeys.get(key) != null;
+ }
+ }
+
+ public short getKeyPrio(Key key, short priority, ObjectContainer
container) {
+ synchronized(pendingKeys) {
+ Object o = pendingKeys.get(key);
+ if(o == null) {
+ // Blah
+ } else if(o instanceof SendableGet) {
+ short p =
((SendableGet)o).getPriorityClass(container);
+ if(p < priority) priority = p;
+ } else { // if(o instanceof SendableGet[]) {
+ SendableGet[] gets = (SendableGet[]) o;
+ for(int i=0;i<gets.length;i++) {
+ short p =
gets[i].getPriorityClass(container);
+ if(p < priority) priority = p;
+ }
+ }
+ }
+ return priority;
+ }
+
+ public SendableGet[] getClientsForPendingKey(Key key, ObjectContainer
container) {
+ Object o;
+ synchronized(pendingKeys) {
+ o = pendingKeys.get(key);
+ }
+ if(o == null) {
+ return null;
+ } else if(o instanceof SendableGet) {
+ SendableGet get = (SendableGet) o;
+ return new SendableGet[] { get };
+ } else {
+ return (SendableGet[]) o;
+ }
+ }
+
+ protected boolean inPendingKeys(SendableGet req, Key key,
ObjectContainer container) {
+ Object o;
+ synchronized(pendingKeys) {
+ o = pendingKeys.get(key);
+ }
+ if(o == null) {
+ return false;
+ } else if(o instanceof SendableGet) {
+ return o == req;
+ } else {
+ SendableGet[] gets = (SendableGet[]) o;
+ for(int i=0;i<gets.length;i++)
+ if(gets[i] == req) return true;
+ }
+ return false;
+ }
+
+ public long countQueuedRequests(ObjectContainer container) {
+ if(pendingKeys != null)
+ return pendingKeys.size();
+ else return 0;
+ }
+
+
}
Added: branches/db4o/freenet/src/freenet/client/async/PendingKeyItem.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/PendingKeyItem.java
(rev 0)
+++ branches/db4o/freenet/src/freenet/client/async/PendingKeyItem.java
2008-07-04 14:28:59 UTC (rev 20993)
@@ -0,0 +1,73 @@
+package freenet.client.async;
+
+import com.db4o.ObjectContainer;
+
+import freenet.keys.Key;
+import freenet.node.SendableGet;
+import freenet.node.SendableRequest;
+
+public class PendingKeyItem {
+
+ final long nodeDBHandle;
+ final Key key;
+ private SendableGet[] getters;
+
+ PendingKeyItem(Key key, SendableGet getter, long nodeDBHandle) {
+ this.key = key;
+ this.getters = new SendableGet[] { getter };
+ this.nodeDBHandle = nodeDBHandle;
+ }
+
+ public void addGetter(SendableGet getter) {
+ for(int i=0;i<getters.length;i++) {
+ if(getters[i] == getter) return;
+ }
+ SendableGet[] newGetters = new SendableGet[getters.length+1];
+ System.arraycopy(getters, 0, newGetters, 0, getters.length);
+ newGetters[getters.length] = getter;
+ getters = newGetters;
+ }
+
+ /**
+ * @param getter
+ * @return True if the getter was removed. Caller should check
isEmpty() afterwards.
+ */
+ public boolean removeGetter(SendableGet getter) {
+ int found = 0;
+ for(int i=0;i<getters.length;i++) {
+ if(getters[i] == getter) found++;
+ }
+ if(found == 0) return false;
+ if(found == getters.length)
+ getters = new SendableGet[0];
+ else {
+ SendableGet[] newGetters = new
SendableGet[getters.length - found];
+ int x = 0;
+ for(int i=0;i<getters.length;i++) {
+ if(getters[i] == getter) continue;
+ newGetters[x++] = getters[i];
+ }
+ getters = newGetters;
+ }
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return getters.length == 0;
+ }
+
+ public boolean hasGetter(SendableRequest req) {
+ for(int i=0;i<getters.length;i++)
+ if(getters[i] == req) return true;
+ return false;
+ }
+
+ public SendableGet[] getters() {
+ return getters;
+ }
+
+ public void objectOnActivate(ObjectContainer container) {
+ container.activate(key, 5);
+ }
+
+}
\ No newline at end of file
Modified: branches/db4o/freenet/src/freenet/node/Node.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/Node.java 2008-07-04 13:58:46 UTC
(rev 20992)
+++ branches/db4o/freenet/src/freenet/node/Node.java 2008-07-04 14:28:59 UTC
(rev 20993)
@@ -723,6 +723,7 @@
Db4o.configure().objectClass(freenet.client.async.RegisterMe.class).objectField("core").indexed(true);
Db4o.configure().objectClass(freenet.client.async.RegisterMe.class).objectField("key").indexed(true);
Db4o.configure().objectClass(freenet.client.async.PersistentCooldownQueueItem.class).objectField("time").indexed(true);
+
Db4o.configure().objectClass(freenet.client.async.PendingKeyItem.class).objectField("key").indexed(true);
/** Maybe we want a different query evaluation mode?
* At the moment, a big splitfile insert will result in one
SingleBlockInserter
* for every key, which means one RegisterMe for each ... this
results in a long pause