Marking fraction of already checked keys as searched

This commit is contained in:
armin 2018-04-27 23:38:52 +02:00
parent 1e149be221
commit 1e2b04a75c
5 changed files with 67 additions and 11 deletions

View file

@ -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)};
} }

View file

@ -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();
} }

View file

@ -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);
} }
} }
} }

View file

@ -21,13 +21,15 @@ 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;
this.depth = depth; this.depth = depth;
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");
@ -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;

View file

@ -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();
} }