| 23 | |
| 24 | @Singleton |
| 25 | class Dandelion(): |
| 26 | def __init__(self): |
| 27 | # currently assignable child stems |
| 28 | self.stem = [] |
| 29 | # currently assigned parent <-> child mappings |
| 30 | self.nodeMap = {} |
| 31 | # currently existing objects in stem mode |
| 32 | self.hashMap = {} |
| 33 | # when to rerandomise routes |
| 34 | self.refresh = time() + REASSIGN_INTERVAL |
| 35 | self.lock = RLock() |
| 36 | |
| 37 | def poissonTimeout(self, start=None, average=0): |
| 38 | if start is None: |
| 39 | start = time() |
| 40 | if average == 0: |
| 41 | average = FLUFF_TRIGGER_MEAN_DELAY |
| 42 | return start + expovariate(1.0/average) + FLUFF_TRIGGER_FIXED_DELAY |
| 43 | |
| 44 | def addHash(self, hashId, source=None, stream=1): |
| 45 | if not state.dandelion: |
| 46 | return |
| 47 | with self.lock: |
| 48 | self.hashMap[hashId] = Stem( |
| 49 | self.getNodeStem(source), |
| 50 | stream, |
| 51 | self.poissonTimeout()) |
| 52 | |
| 53 | def setHashStream(self, hashId, stream=1): |
| 54 | with self.lock: |
| 55 | if hashId in self.hashMap: |
| 56 | self.hashMap[hashId] = Stem( |
| 57 | self.hashMap[hashId].child, |
| 58 | stream, |
| 59 | self.poissonTimeout()) |
| 60 | |
| 61 | def removeHash(self, hashId, reason="no reason specified"): |
| 62 | logging.debug("%s entering fluff mode due to %s.", ''.join('%02x'%ord(i) for i in hashId), reason) |
| 63 | with self.lock: |
| 64 | try: |
| 65 | del self.hashMap[hashId] |
| 66 | except KeyError: |
| 67 | pass |
| 68 | |
| 69 | def hasHash(self, hashId): |
| 70 | return hashId in self.hashMap |
| 71 | |
| 72 | def objectChildStem(self, hashId): |
| 73 | return self.hashMap[hashId].child |
| 74 | |
| 75 | def maybeAddStem(self, connection): |
| 76 | # fewer than MAX_STEMS outbound connections at last reshuffle? |
| 77 | with self.lock: |
| 78 | if len(self.stem) < MAX_STEMS: |
| 79 | self.stem.append(connection) |
| 80 | for k in (k for k, v in self.nodeMap.iteritems() if v is None): |
| 81 | self.nodeMap[k] = connection |
| 82 | for k, v in {k: v for k, v in self.hashMap.iteritems() if v.child is None}.iteritems(): |
no outgoing calls
no test coverage detected