Example #1
0
    def test_init(self):

        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=1)

        # No arguments
        dq = DistributedQueue(node, conn)
        assert dq.node == node
        assert dq.conn == conn
        assert dq.myWsize == 64
        assert dq.master is True
        assert dq.otherWsize == 64
        assert len(dq.queueList) == 1
        assert dq.maxSeq == 2**8
        assert dq.maxCommsSeq == 2**8
        assert dq.status == dq.STAT_IDLE
        assert dq.comms_seq == 0
        assert dq.acksWaiting == 0
        assert len(dq.waitAddAcks) == 0
        assert dq.expectedSeq == 0

        # No arguments, not controlling node
        dq = DistributedQueue(node2, conn)
        assert dq.node == node2
        assert dq.conn == conn
        assert dq.myWsize == 64
        assert dq.master is False
        assert dq.otherWsize == 64
        assert len(dq.queueList) == 1
        assert dq.maxSeq == 2**8
        assert dq.status == dq.STAT_IDLE
        assert dq.comms_seq == 0
        assert dq.acksWaiting == 0
        assert len(dq.waitAddAcks) == 0
        assert dq.expectedSeq == 0

        # Set arguments

        dq = DistributedQueue(node, conn, False, 1, 2, 3, 4)
        assert dq.node == node
        assert dq.conn == conn
        assert dq.master is False
        assert dq.myWsize == 1
        assert dq.otherWsize == 2
        assert len(dq.queueList) == 3
        assert dq.maxSeq == 4
        assert dq.status == dq.STAT_IDLE
        assert dq.comms_seq == 0
        assert dq.acksWaiting == 0
        assert len(dq.waitAddAcks) == 0
        assert dq.expectedSeq == 0
Example #2
0
    def test_comm_timeout(self):
        self.callback_storage = []

        def add_callback(result):
            self.callback_storage.append(result)

        sim_reset()
        alice = QuantumNode("Alice", 1)
        bob = QuantumNode("Bob", 2)

        conn = ClassicalFibreConnection(alice, bob, length=0.01)
        aliceDQ = DistributedQueue(alice, conn)

        aliceDQ.add_callback = add_callback

        num_adds = 100
        aliceProto = TestProtocol(alice, aliceDQ, 1, maxNum=num_adds)

        nodes = [alice, bob]

        conns = [(conn, "dqp_conn", [aliceProto])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        sim_run(5000)

        expected_qid = 0
        expected_results = [(aliceDQ.DQ_TIMEOUT, expected_qid,
                             qseq % aliceDQ.myWsize, [alice.name, qseq])
                            for qseq in range(num_adds)]

        # Check that all attempted add's timed out
        self.assertEqual(self.callback_storage, expected_results)

        # Check that alice's distributed queue has no outstanding add acks
        self.assertEqual(aliceDQ.waitAddAcks, {})

        # Check that all of the local queues are empty
        for local_queue in aliceDQ.queueList:
            self.assertEqual(local_queue.queue, [])
            self.assertEqual(local_queue.sequence_to_item, {})

        # Check that we incremented the comms_seq
        self.assertEqual(aliceDQ.comms_seq, num_adds)
Example #3
0
    def test_add_basic(self):

        # Set up two nodes and run a simulation in which items
        # are randomly added at specific time intervals
        sim_reset()
        alice = QuantumNode("Alice", 1)
        bob = QuantumNode("Bob", 2)

        conn = ClassicalFibreConnection(alice, bob, length=.0001)
        aliceDQ = DistributedQueue(alice, conn)
        bobDQ = DistributedQueue(bob, conn)

        aliceProto = TestProtocol(alice,
                                  aliceDQ,
                                  1,
                                  maxNum=aliceDQ.maxSeq // 2)
        bobProto = TestProtocol(bob, bobDQ, 1, maxNum=bobDQ.maxSeq // 2)

        nodes = [
            (alice, [aliceProto]),
            (bob, [bobProto]),
        ]
        conns = [(conn, "dqp_conn", [aliceProto, bobProto])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        sim_run(50000)

        # Check the Queue contains ordered elements from Alice and Bob
        qA = aliceDQ.queueList[0].sequence_to_item
        qB = bobDQ.queueList[0].sequence_to_item

        # First they should have the same length
        self.assertGreater(len(qA), 0)
        self.assertEqual(len(qA), len(qB))

        # Check the items are the same and the sequence numbers are ordered
        count = 0
        for k in range(len(qA)):
            self.assertEqual(qA[k].request, qB[k].request)
            self.assertEqual(qA[k].seq, qB[k].seq)
            self.assertEqual(qA[k].seq, count)
            count = count + 1
Example #4
0
    def test_full_wraparound(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=25)

        wSize = 2
        maxSeq = 6
        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True,
                              myWsize=wSize,
                              otherWsize=wSize,
                              maxSeq=maxSeq)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True,
                               myWsize=wSize,
                               otherWsize=wSize,
                               maxSeq=maxSeq)
        dq.connect_to_peer_protocol(dq2, conn)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        for timestep in range(1, maxSeq + 1):
            dq.add(timestep, 0)
            sim_run(timestep * 1000000)
            dq.queueList[0].queue[timestep - 1].ready = True
            dq2.queueList[0].queue[timestep - 1].ready = True

        dq.queueList[0].pop()
        dq2.queueList[0].pop()
        dq.add(maxSeq, 0)
        sim_run(maxSeq * 100000)

        dq.queueList[0].pop()
        dq2.queueList[0].pop()
        dq.queueList[0].pop()
        dq2.queueList[0].pop()
Example #5
0
    def test_slave_add_while_waiting(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=25)

        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True)
        dq.connect_to_peer_protocol(dq2, conn)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        # Add one request for both master and slave
        create_id = 0
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq.add(request=request, qid=0)
        create_id = 1
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq2.add(request=request, qid=0)

        # Wait for slaves add to arrive but not the ack
        run_time = dq.comm_delay * (3 / 4)
        sim_run(run_time)

        # Add request from master
        create_id = 2
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq.add(request=request, qid=0)

        # Make sure things are added
        run_time = dq.comm_delay * 4
        sim_run(run_time)

        self.ready_items(dq.queueList[0])
        self.ready_items(dq2.queueList[0])
        self.check_local_queues(dq.queueList[0], dq2.queueList[0])
Example #6
0
    def test_resend_acks(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=25)

        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True)
        dq.connect_to_peer_protocol(dq2, conn)

        storage1 = []
        storage2 = []

        def callback1(result):
            storage1.append(result)

        def callback2(result):
            storage2.append(result)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()
        dq.add_callback = callback1
        dq2.add_callback = callback2

        # Add one request
        create_id = 0
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq2.add(request=request, qid=0)
        run_time = dq.comm_delay * dq.timeout_factor
        sim_run(run_time)

        # Set way to short timeout (to force resend)
        dq2.timeout_factor = 1 / 2

        # Add one request (slave)
        create_id = 1
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq2.add(request=request, qid=0)
        run_time += (dq.comm_delay + 1) * 4
        sim_run(run_time)

        # Set to correct factor again
        dq2.timeout_factor = 2

        create_id = 2
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq.add(request=request, qid=0)
        dq2.add(request=request, qid=0)
        run_time += dq.comm_delay * dq.timeout_factor
        sim_run(run_time)

        self.assertEqual(len(storage1), 4)
        self.assertEqual(len(storage2), 4)

        q_seqs1 = [res[2] for res in storage1]
        q_seqs2 = [res[2] for res in storage2]

        for qseq in range(4):
            for q_seqs in [q_seqs1, q_seqs2]:
                # TODO do we care about the ordering?
                self.assertIn(qseq, q_seqs)
Example #7
0
    def test_unordered_subsequent_acks(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=25)

        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True)
        dq.connect_to_peer_protocol(dq2, conn)

        storage1 = []
        storage2 = []

        def callback1(result):
            storage1.append(result)

        def callback2(result):
            storage2.append(result)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        # Add three requests (master)
        dq.add_callback = callback1
        dq2.add_callback = callback2
        for create_id in range(3):
            request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True,
                                       False, False, True)
            dq.add(request=request, qid=0)
        run_time = dq.comm_delay * dq.timeout_factor
        sim_run(run_time)
        self.assertEqual(len(storage1), 3)
        self.assertEqual(len(storage2), 3)
        q_seqs1 = [res[2] for res in storage1]
        q_seqs2 = [res[2] for res in storage2]
        self.assertEqual(q_seqs1, [0, 1, 2])
        self.assertEqual(q_seqs2, [0, 1, 2])

        # Remove one request (such that next queue seq will be 0 again)
        dq.remove_item(0, 1)
        dq2.remove_item(0, 1)
        storage1 = []
        storage2 = []

        # Add requests from master and slave
        create_id = 3
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq.add(request=request, qid=0)
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq2.add(request=request, qid=0)

        run_time += dq.comm_delay * dq.timeout_factor
        sim_run(run_time)

        self.assertEqual(len(storage1), 2)
        self.assertEqual(len(storage2), 2)
        q_seqs1 = [res[2] for res in storage1]
        q_seqs2 = [res[2] for res in storage2]
        self.assertIn(1, q_seqs1)
        self.assertIn(3, q_seqs1)
        self.assertIn(1, q_seqs2)
        self.assertIn(3, q_seqs2)
Example #8
0
    def test_lossy_comms_wraparound(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=0.1)
        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True)
        dq.connect_to_peer_protocol(dq2, conn)

        self.lost_messages = 0
        self.lost_seq = dq.myWsize + 1

        def faulty_send_msg(cmd, data, clock):
            if self.lost_messages == 0 and clock[0] == self.lost_seq:
                self.lost_messages += 1
            else:
                dq.conn.put_from(dq.myID, (cmd, data, clock))

        dq.send_msg = faulty_send_msg

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        num_adds = 0
        r = 1
        curr_time = 0
        import pdb
        while num_adds < 2 * dq.maxCommsSeq:
            add_delay = 2
            for i in range(dq.myWsize):
                request = SchedulerRequest(0, 0, 0, 0, i, 0, 0, True, False,
                                           False, True)
                dq.add(request)
                sim_run(curr_time + (i + 1) * add_delay)
                curr_time += add_delay

            for j in range(dq2.myWsize):
                request = SchedulerRequest(0, 0, 0, 0, j, 0, 0, True, False,
                                           False, True)
                dq2.add(request)
                sim_run(curr_time + (j + 1) * add_delay)
                curr_time += add_delay

            num_adds += dq.myWsize
            num_adds += dq2.myWsize
            run_time = r * dq.comm_delay * 4
            sim_run(curr_time + run_time)
            curr_time += run_time
            r += 1
            self.ready_items(dq.queueList[0])
            self.ready_items(dq2.queueList[0])
            self.check_local_queues(dq.queueList[0], dq2.queueList[0])

            for i in range(dq.myWsize + dq2.myWsize):
                dq.local_pop()
                dq2.local_pop()
Example #9
0
    def test_full_queue(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=0.0001)

        dq = DistributedQueue(node, conn, numQueues=3)
        dq2 = DistributedQueue(node2, conn, numQueues=3)
        dq.connect_to_peer_protocol(dq2, conn)

        storage = []

        def callback(result):
            storage.append(result)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        for j in range(dq.maxSeq):
            dq.add(request=j + 1, qid=0)

        sim_run(1000)

        with self.assertRaises(LinkLayerException):
            dq.add(request=0, qid=0)

        dq2.add_callback = callback
        for j in range(dq2.maxSeq):
            dq2.add(request=j + 1, qid=1)

        sim_run(2000)

        with self.assertRaises(LinkLayerException):
            dq2.add(request=dq2.maxSeq + 1, qid=1)

        self.assertEqual(len(storage), 257)
        self.assertEqual(storage[-1], (dq2.DQ_ERR, 1, None, dq2.maxSeq + 1))
        storage = []

        for j in range(dq.maxSeq):
            if j % 2:
                dq.add(request=j + 1, qid=2)
            else:
                dq2.add(request=j + 1, qid=2)

        dq2.add(request=dq.maxSeq + 1, qid=2)
        sim_run(3000)

        with self.assertRaises(LinkLayerException):
            dq.add(request=0, qid=2)

        self.assertEqual(len(storage), 257)
        self.assertEqual(storage[-1], (dq2.DQ_REJECT, 2, 0, dq2.maxSeq + 1))
Example #10
0
    def test_remove(self):
        # Set up two nodes and run a simulation in which items
        # are randomly added at specific time intervals
        sim_reset()
        alice = QuantumNode("Alice", 1)
        bob = QuantumNode("Bob", 2)

        conn = ClassicalFibreConnection(alice, bob, length=.0001)
        aliceDQ = DistributedQueue(alice, conn)
        bobDQ = DistributedQueue(bob, conn)

        aliceProto = TestProtocol(alice, aliceDQ, 1)
        bobProto = TestProtocol(bob, bobDQ, 1)

        nodes = [
            (alice, [aliceProto]),
            (bob, [bobProto]),
        ]
        conns = [(conn, "dqp_conn", [aliceProto, bobProto])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        sim_run(1000)

        # Check the Queue contains ordered elements from Alice and Bob
        queueA = aliceDQ.queueList[0]
        queueB = bobDQ.queueList[0]
        qA = queueA.sequence_to_item
        qB = queueB.sequence_to_item

        # Make all the items ready
        for seq in qA:
            queueA.ack(seq)
            queueA.ready(seq)
        for seq in qB:
            queueB.ack(seq)
            queueB.ready(seq)

        # First they should have the same length
        self.assertGreater(len(qA), 0)
        self.assertEqual(len(qA), len(qB))

        # Check the items are the same and the sequence numbers are ordered
        count = 0
        for k in range(len(qA)):
            self.assertEqual(qA[k].request, qB[k].request)
            self.assertEqual(qA[k].seq, qB[k].seq)
            self.assertEqual(qA[k].seq, count)
            count = count + 1

        # Check that we can remove the items (locally) at both nodes
        rqid = 0
        rqseqs = set([randint(0, len(qA) - 1) for t in range(10)])
        for qseq in rqseqs:
            q_item = aliceDQ.remove_item(rqid, qseq)
            self.assertIsNotNone(q_item)
            self.assertFalse(aliceDQ.queueList[rqid].contains(qseq))

        # Check that we can pop the remaining items in the correct order
        remaining = set(range(len(qB))) - rqseqs
        for qseq in remaining:
            q_item = aliceDQ.local_pop(rqid)
            self.assertEqual(q_item.seq, qseq)
            self.assertIsNotNone(q_item)
Example #11
0
    def test_lost_add_slave(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=0.0001)

        dq = DistributedQueue(node, conn, numQueues=3)
        dq2 = DistributedQueue(node2, conn, numQueues=3)
        dq.connect_to_peer_protocol(dq2, conn)

        self.lost_messages = defaultdict(int)

        def faulty_send_add(cmd, data, clock):
            if cmd == dq2.CMD_ADD:
                _, cseq, qid, qseq, request = data
                if self.lost_messages[(cseq, qid, qseq)] >= 1:
                    dq2.conn.put_from(dq2.myID, (cmd, data, clock))
                else:
                    self.lost_messages[(cseq, qid, qseq)] += 1
            else:
                dq2.conn.put_from(dq2.myID, (cmd, data, clock))

        def faulty_send_ack(cmd, data, clock):
            if cmd == dq.CMD_ADD_ACK:
                _, ackd_id, qseq = data
                if self.lost_messages[(ackd_id, qseq)] >= 1:
                    dq.conn.put_from(dq.myID, (cmd, data, clock))
                else:
                    self.lost_messages[(ackd_id, qseq)] += 1
            else:
                dq.conn.put_from(dq.myID, (cmd, data, clock))

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        dq2.send_msg = faulty_send_add
        dq.send_msg = faulty_send_ack

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        reqs = []
        num_reqs = 10
        for i in range(num_reqs):
            req = [node2.nodeID, i]
            reqs.append(req)
            dq2.add(req)
            sim_run(0.1 * (i + 1))

        sim_run(200)

        # Check that all add and add_ack messages were lost once
        for v in self.lost_messages.values():
            self.assertEqual(v, 1)

        # Check that the item successfully got added
        self.assertEqual(len(dq.queueList[0].queue), 10)
        self.assertEqual(len(dq2.queueList[0].queue), 10)

        for i, expected_req in zip(range(num_reqs), reqs):
            item1 = dq.queueList[0].queue[i]
            item2 = dq2.queueList[0].queue[i]
            self.assertEqual(item1.request, expected_req)
            self.assertEqual(item2.request, expected_req)
Example #12
0
    def test_random_add_remove(self):
        sim_reset()
        node = QuantumNode("TestNode 1", 1)
        node2 = QuantumNode("TestNode 2", 2)
        conn = ClassicalFibreConnection(node, node2, length=25)

        dq = DistributedQueue(node,
                              conn,
                              numQueues=3,
                              throw_local_queue_events=True)
        dq2 = DistributedQueue(node2,
                               conn,
                               numQueues=3,
                               throw_local_queue_events=True)
        dq.connect_to_peer_protocol(dq2, conn)

        nodes = [
            (node, [dq]),
            (node2, [dq2]),
        ]
        conns = [(conn, "dq_conn", [dq, dq2])]

        network = EasyNetwork(name="DistQueueNetwork",
                              nodes=nodes,
                              connections=conns)
        network.start()

        create_id = 0
        for _ in range(20):
            # Add random requests to master
            num_reqs_master = randint(0, 3)
            for _ in range(num_reqs_master):
                request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True,
                                           False, False, True)
                try:
                    dq.add(request=request, qid=0)
                except LinkLayerException:
                    # Full queue
                    pass
                create_id += 1

            # Add random requests to slave
            num_reqs_slave = randint(0, 3)
            for _ in range(num_reqs_slave):
                request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True,
                                           False, False, True)
                try:
                    dq2.add(request=request, qid=0)
                except LinkLayerException:
                    # Full queue
                    pass
                create_id += 1

            # Randomly remove things for both
            num_pop = randint(0, 6)
            for _ in range(num_pop):
                dq.local_pop(qid=0)

            # Run for random fraction of timeout
            r = randint(1, 20)
            run_time = dq.comm_delay * dq.timeout_factor * (r / 10)
            sim_run(run_time)

        # Make sure things are not in flight
        sim_run()

        self.ready_items(dq.queueList[0])
        self.ready_items(dq2.queueList[0])
        self.check_local_queues(dq.queueList[0], dq2.queueList[0])

        # Add one request for both master and slave
        create_id = 0
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq.add(request=request, qid=0)
        create_id = 1
        request = SchedulerRequest(0, 0, 0, 0, create_id, 0, 0, True, False,
                                   False, True)
        dq2.add(request=request, qid=0)