Marking fraction of already checked keys as searched
This commit is contained in:
parent
1e149be221
commit
1e2b04a75c
5 changed files with 67 additions and 11 deletions
|
@ -35,7 +35,7 @@ int main() {
|
||||||
thread* threads = new thread[numThreads];
|
thread* threads = new thread[numThreads];
|
||||||
cout << "Starting " << numThreads << " threads" << endl;
|
cout << "Starting " << numThreads << " threads" << endl;
|
||||||
|
|
||||||
numThreads = 1;
|
//numThreads = 1;
|
||||||
for (unsigned int i = 0; i < numThreads; i++) {
|
for (unsigned int i = 0; i < numThreads; i++) {
|
||||||
threads[i] = thread{bf::Brainflyer(i, "127.0.0.1", 26765, key)};
|
threads[i] = thread{bf::Brainflyer(i, "127.0.0.1", 26765, key)};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,19 +15,19 @@ import org.slf4j.LoggerFactory;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CnC {
|
public class CnC {
|
||||||
final static Logger log = LoggerFactory.getLogger(CnC.class);
|
static final Logger log = LoggerFactory.getLogger(CnC.class);
|
||||||
|
|
||||||
public static final int PORT = 26765;
|
public static final int PORT = 26765;
|
||||||
// Invariant: positive long (2^63-1) must be able to hold all bits handled here
|
// Invariant: positive long (2^63-1) must be able to hold all bits handled here
|
||||||
public static final int MAX_BITS = 62;
|
public static final int MAX_BITS = 62;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
KeyServer kts = KSFactory.build(54, 30, 90, TimeUnit.MINUTES);
|
KeyServer kts = KSFactory.build(54, 30, 90, TimeUnit.MINUTES, 0.62f);
|
||||||
CommServer server = new CommServer(PORT, kts);
|
CommServer server = new CommServer(PORT, kts);
|
||||||
try {
|
try {
|
||||||
server.listen();
|
server.listen();
|
||||||
} catch (CommException e) {
|
} catch (CommException e) {
|
||||||
log.error("CommServer couldn't be started");
|
log.error("CommServer couldn't be started", e);
|
||||||
} finally {
|
} finally {
|
||||||
server.stop();
|
server.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,30 @@ import org.btcollider.cnc.keysrv.impl.keytree.KeyTreeServer;
|
||||||
import org.btcollider.cnc.keysrv.impl.multistage.MultiStagedServer;
|
import org.btcollider.cnc.keysrv.impl.multistage.MultiStagedServer;
|
||||||
|
|
||||||
public class KSFactory {
|
public class KSFactory {
|
||||||
|
|
||||||
|
public static KeyServer build(int index, int depth, long maxWorkSpan) {
|
||||||
|
return build(index, depth, maxWorkSpan, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
public static KeyServer build(int index, int depth, long maxWorkSpan, TimeUnit timeUnit) {
|
public static KeyServer build(int index, int depth, long maxWorkSpan, TimeUnit timeUnit) {
|
||||||
|
return build(index, depth, maxWorkSpan, timeUnit, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyServer build(int index, int depth, long maxWorkSpan, TimeUnit timeUnit, float pruneFraction) {
|
||||||
|
assert (pruneFraction >= 0.0 && pruneFraction <= 1.0);
|
||||||
|
|
||||||
|
long maxKey = ((long) 1 << index) | (( (long) 1 << index) - 1);
|
||||||
|
long pruneKey = (long) Math.floor(maxKey * pruneFraction);
|
||||||
|
|
||||||
|
return build(index, depth, maxWorkSpan, timeUnit, pruneKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyServer build(int index, int depth, long maxWorkSpan, TimeUnit timeUnit, long pruneKey) {
|
||||||
if (depth == 25) {
|
if (depth == 25) {
|
||||||
return new KeyTreeServer(index, depth, timeUnit.toMillis(maxWorkSpan));
|
return new KeyTreeServer(index, depth, timeUnit.toMillis(maxWorkSpan), pruneKey);
|
||||||
} else {
|
} else {
|
||||||
return new MultiStagedServer(index, depth, timeUnit.toMillis(maxWorkSpan));
|
return new MultiStagedServer(index, depth, timeUnit.toMillis(maxWorkSpan), pruneKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class KeyTreeServer implements KeyServer {
|
||||||
private int index;
|
private int index;
|
||||||
private int depth;
|
private int depth;
|
||||||
|
|
||||||
public KeyTreeServer(int index, int depth, long maxWorkSpan) {
|
public KeyTreeServer(int index, int depth, long maxWorkSpan, long pruneKey) {
|
||||||
assert Math.pow(2, CnC.MAX_BITS) <= Long.MAX_VALUE;
|
assert Math.pow(2, CnC.MAX_BITS) <= Long.MAX_VALUE;
|
||||||
assert index < CnC.MAX_BITS && depth <= CnC.MAX_BITS;
|
assert index < CnC.MAX_BITS && depth <= CnC.MAX_BITS;
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ public class KeyTreeServer implements KeyServer {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.root = generateKeyTree(depth);
|
this.root = generateKeyTree(depth);
|
||||||
|
|
||||||
|
if (pruneKey > 0) prune(pruneKey);
|
||||||
|
|
||||||
if (maxWorkSpan > 0) {
|
if (maxWorkSpan > 0) {
|
||||||
log.info("Starting KeyTree concierge");
|
log.info("Starting KeyTree concierge");
|
||||||
ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor();
|
ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
@ -113,6 +115,40 @@ public class KeyTreeServer implements KeyServer {
|
||||||
return nodeName;
|
return nodeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prunes every branch strictly smaller than pruneKey
|
||||||
|
*
|
||||||
|
* @param prune
|
||||||
|
* The smallest valid key in the keyspace Must be at least as large
|
||||||
|
* as the smallest key in the tree Must be at most as large as the
|
||||||
|
* largest key in the tree
|
||||||
|
*/
|
||||||
|
private void prune(Long pruneKey) {
|
||||||
|
BitSet pkBS = BitSet.valueOf(new long[] { pruneKey });
|
||||||
|
int curIdx = pkBS.length() - 1;
|
||||||
|
assert (curIdx == this.index); // at least the smallest, at most the largest key in the tree
|
||||||
|
// -> pos of highest bits is equal
|
||||||
|
|
||||||
|
recPrune(pkBS, this.root, curIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recPrune(BitSet pruneKey, KeyTree node, int curIdx) {
|
||||||
|
if (node.getValue() && !pruneKey.get(curIdx)) { // node[ix] = 0 and pruneK[ix] = 1 -> path smaller
|
||||||
|
node.setSearched(true);
|
||||||
|
return;
|
||||||
|
} else if (!node.getValue() && pruneKey.get(curIdx)) { // node[ix] = 1 and pruneK[ix] = 0 -> path
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isLeaf()) { // end reached
|
||||||
|
assert (curIdx == 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recPrune(pruneKey, node.getLeft(), curIdx-1);
|
||||||
|
recPrune(pruneKey, node.getRight(), curIdx-1);
|
||||||
|
}
|
||||||
|
|
||||||
private void markInWork(BitSet key) {
|
private void markInWork(BitSet key) {
|
||||||
KeyTree keyTreePointer = root;
|
KeyTree keyTreePointer = root;
|
||||||
|
|
||||||
|
|
|
@ -25,21 +25,22 @@ public class MultiStagedServer implements KeyServer {
|
||||||
private int subIndex;
|
private int subIndex;
|
||||||
private long maxWorkSpan;
|
private long maxWorkSpan;
|
||||||
|
|
||||||
public MultiStagedServer(int index, int depth, long maxWorkSpan) {
|
public MultiStagedServer(int index, int depth, long maxWorkSpan, long pruneKey) {
|
||||||
this.remainingDepth = depth - PARTITION_DEPTH;
|
this.remainingDepth = depth - PARTITION_DEPTH;
|
||||||
this.subIndex = index - PARTITION_DEPTH;
|
this.subIndex = index - PARTITION_DEPTH;
|
||||||
this.maxWorkSpan = maxWorkSpan;
|
this.maxWorkSpan = maxWorkSpan;
|
||||||
|
|
||||||
// Build a reasonably sized KeyTreeServer with disabled KTConcierge service
|
// Build a reasonably sized KeyTreeServer with disabled KTConcierge service
|
||||||
// This represents the first partitioning of the key space
|
// This represents the first partitioning of the key space
|
||||||
this.primKTS = new KeyTreeServer(index, PARTITION_DEPTH, 0);
|
this.primKTS = new KeyTreeServer(index, PARTITION_DEPTH, 0, pruneKey);
|
||||||
// Get a random starting range from the primary KTS, this range is still too huge
|
// Get a random starting range from the primary KTS, this range is still too huge
|
||||||
this.partition = primKTS.getRange();
|
this.partition = primKTS.getRange();
|
||||||
// Start a secondary KTS to partition remaining key space in currentRange
|
// Start a secondary KTS to partition remaining key space in currentRange
|
||||||
// This represents the actual work-horse KeyTreeServer for the current partition with
|
// This represents the actual work-horse KeyTreeServer for the current partition with
|
||||||
// enabled KTConcierge service.
|
// enabled KTConcierge service.
|
||||||
// Needs subindex+1 because starting bit always set to 1
|
// Needs subindex+1 because starting bit always set to 1
|
||||||
this.secKTS = new KeyTreeServer(subIndex+1, remainingDepth, maxWorkSpan);
|
long subPrune = ((long) 1 << subIndex+1) | ( (((long) 1 << subIndex+1) - 1) & pruneKey );
|
||||||
|
this.secKTS = new KeyTreeServer(subIndex+1, remainingDepth, maxWorkSpan, subPrune);
|
||||||
|
|
||||||
this.keyRangeBuffer = new KeyRangeBuffer(maxWorkSpan);
|
this.keyRangeBuffer = new KeyRangeBuffer(maxWorkSpan);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +59,7 @@ public class MultiStagedServer implements KeyServer {
|
||||||
log.info("Subrange {} finished. Opening new partition.", partition);
|
log.info("Subrange {} finished. Opening new partition.", partition);
|
||||||
primKTS.setSearched(partition);
|
primKTS.setSearched(partition);
|
||||||
partition = primKTS.getRange();
|
partition = primKTS.getRange();
|
||||||
secKTS = new KeyTreeServer(subIndex+1, remainingDepth, maxWorkSpan);
|
secKTS = new KeyTreeServer(subIndex+1, remainingDepth, maxWorkSpan, 0);
|
||||||
return getRange();
|
return getRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue