예제 #1
0
    def test_init(self) -> None:
        h: History

        # empty history
        #
        with self.assertRaises(ValueError):
            h = History([])

        # transaction order
        #
        with self.assertRaises(ValueError):
            h = History([
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"), Result(), 0, 8,
                    0.0, 0.0),
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"),
                    Result(),
                    0,
                    0,
                    0.0,
                    0.0,
                ),
            ])

        h = self.get_history()
예제 #2
0
    def gen_final_txn(txn_id: int, obj_list: List[DBObject]) -> Transaction:
        """
        Generate final transaction to reads all objects
        This transaction should happend without concurrency
        """
        ops: List[Operation] = [
            Operation(Operation.Type.SET_ISOLATION, isolation_level="serializable"),
            Operation(Operation.Type.BEGIN),
        ]
        for obj in obj_list:
            ops.append(Operation(Operation.Type.READ, obj=obj))

        ops.append(Operation(Operation.Type.COMMIT))
        return Transaction(txn_id, ops)
예제 #3
0
    def gen_init_txn(txn_id: int, obj_list: List[DBObject]) -> Transaction:
        """
        Generate initial transaction to set initial value for objects
        This transaction should happend without concurrency
        """
        ops: List[Operation] = [
            Operation(Operation.Type.SET_ISOLATION, isolation_level="serializable"),
            Operation(Operation.Type.BEGIN),
        ]
        for obj in obj_list:
            ops.append(Operation(Operation.Type.WRITE, obj=obj, value=obj_ver[obj.id]))

        ops.append(Operation(Operation.Type.COMMIT))
        return Transaction(txn_id, ops)
예제 #4
0
        def gen_op(
            obj_list: List[DBObject],
            table_names: List[str],
            write_rate: float,
            predicate_read_rate: float,
            for_update: bool,
            chosen_len: int,
        ) -> List[Operation]:
            """
            Generate a single operation

            By fixing a chosen len across a transaction, it makes it more likely for there to be conflicts
            """
            rnd: float = random.random()
            if rnd < write_rate:
                obj: DBObject = random.choice(obj_list)
                # This creates an object if it doesn't exist
                # Note that we cannot rely on the object being created if obj_ver[obj_id] > 0.
                # This is because obj_ver denotes the order in which the statements are *generated* not executed
                # It is incremental to ensure *uniqueness*, not *order*
                # For instance, "1,2,0,4,3" is a valid value for an object, but "1,2,1,4,3" is not
                #
                obj_ver[obj.id] += 1
                return [
                    Operation(Operation.Type.READ, obj=obj, for_update=for_update),
                    Operation(Operation.Type.WRITE, obj=obj, value=obj_ver[obj.id]),
                ]
            elif write_rate <= rnd < write_rate + predicate_read_rate:
                return [
                    Operation(
                        Operation.Type.PREDICATE_READ,
                        tables=table_names,
                        value=chosen_len,
                        for_update=for_update,
                    )
                ]
            else:
                return [
                    Operation(
                        Operation.Type.READ,
                        obj=random.choice(obj_list),
                        for_update=for_update,
                    )
                ]
예제 #5
0
    def process_txn(obj_list: List[DBObject], conn: DBConn, conn_id: int, txn: Transaction) -> Iterator[HistoryElem]:
        """
        Process a transaction as an iterator
        """
        object_versions: Dict[int, List[int]] = dict()
        try:
            for op in txn.ops:
                invoc: float = time.time()
                ret: Optional[List[Tuple[Any, ...]]]
                if op.type == Operation.Type.WRITE:
                    prev_version = object_versions[op.obj.id] if op.obj.id in object_versions else list()
                    ret = conn.execute(op.stmt(prev_version))
                else:
                    ret = conn.execute(op.stmt())

                if op.type == Operation.Type.PREDICATE_READ:
                    resp: float = time.time()
                    yield HistoryElem(op, Result(value=ret), conn_id, txn.id, invoc, resp)
                    for tup in ret:
                        object_versions[tup[0]] = [int(v) for v in tup[1].strip().split(",")]
                        yield HistoryElem(
                            Operation(Operation.Type.READ, obj=obj_list[tup[0]]),
                            Result(value=[(tup[1],)]),
                            conn_id,
                            txn.id,
                            invoc,
                            resp,
                        )
                else:
                    res: Result = Result(value=ret) if ret is not None else Result()
                    if res.is_ok() and res.is_value():
                        object_versions[op.obj.id] = res.value()
                    yield HistoryElem(op, res, conn_id, txn.id, invoc)
        except Exception as e:
            conn.process_exception(e)
            yield HistoryElem(op, Result(exception=e), conn_id, txn.id, invoc)
예제 #6
0
    def gen_transaction(
        txn_id: int,
        obj_list: List[DBObject],
        table_names: List[str],
        isolation_level: str,
        min_size: int,
        max_size: int,
        abort_rate: float,
        write_rate: float,
        predicate_read_rate: float,
        for_update: bool,
    ) -> Transaction:
        """
        Generates a list of SQL statemtents for a transaction

         <obj_list>: list of objects
         <isolation_level>: isolation level for the transaction
         <min_size>: minimum size of the transaction (in number of operations)
         <max_size>: maximum size of the transaction (in number of operations)
         <abort_rate>: abort rate (domain = [0.0, 1.0])
         <write_rate>: write rate (domain = [0.0, 1.0])
         <predicate_read_rate>: predicate read rate (domain = [0.0, 1.0])
        """

        def gen_op(
            obj_list: List[DBObject],
            table_names: List[str],
            write_rate: float,
            predicate_read_rate: float,
            for_update: bool,
            chosen_len: int,
        ) -> List[Operation]:
            """
            Generate a single operation

            By fixing a chosen len across a transaction, it makes it more likely for there to be conflicts
            """
            rnd: float = random.random()
            if rnd < write_rate:
                obj: DBObject = random.choice(obj_list)
                # This creates an object if it doesn't exist
                # Note that we cannot rely on the object being created if obj_ver[obj_id] > 0.
                # This is because obj_ver denotes the order in which the statements are *generated* not executed
                # It is incremental to ensure *uniqueness*, not *order*
                # For instance, "1,2,0,4,3" is a valid value for an object, but "1,2,1,4,3" is not
                #
                obj_ver[obj.id] += 1
                return [
                    Operation(Operation.Type.READ, obj=obj, for_update=for_update),
                    Operation(Operation.Type.WRITE, obj=obj, value=obj_ver[obj.id]),
                ]
            elif write_rate <= rnd < write_rate + predicate_read_rate:
                return [
                    Operation(
                        Operation.Type.PREDICATE_READ,
                        tables=table_names,
                        value=chosen_len,
                        for_update=for_update,
                    )
                ]
            else:
                return [
                    Operation(
                        Operation.Type.READ,
                        obj=random.choice(obj_list),
                        for_update=for_update,
                    )
                ]

        size: int = random.randint(min_size, max_size)
        # How many times, on average, each txn will write to an object
        #
        AVG_WRITE_PER_OBJECT_PER_TXN: float = (write_rate * 0.5 * (min_size + max_size)) / len(obj_list)

        # This is a bit hacky, but multiplying AVG_WRITE_PER_OBJECT_PER_TXN by
        # the transaction id gives the approximate average size of each object at this point
        # since it approximates sum([AVG_WRITE_PER_OBJECT_PER_TXN] * N_TXN_UNTIL_THIS_POINT)
        #
        AVG_OBJECT_SIZE: int = int(AVG_WRITE_PER_OBJECT_PER_TXN * txn_id)

        ops: List[Operation] = [
            Operation(Operation.Type.SET_ISOLATION, isolation_level=isolation_level),
            Operation(Operation.Type.BEGIN),
        ]

        for _ in range(size):
            # Using this hacky math makes the predicate reads more likely to return
            # interesting queries
            #
            # We intentionally skew in favour of returning less values, which
            # makes this more prone to returning less values, and consequently
            # generating more anti-dependencies
            #
            for op in gen_op(
                obj_list,
                table_names,
                write_rate,
                predicate_read_rate,
                for_update,
                random.randint(int(AVG_OBJECT_SIZE * 0.85), int(AVG_OBJECT_SIZE * 1.35)),
            ):
                ops.append(op)

        if random.random() < abort_rate:
            ops.append(Operation(Operation.Type.ROLLBACK))
        else:
            ops.append(Operation(Operation.Type.COMMIT))

        return Transaction(txn_id, ops)
예제 #7
0
 def get_g1b_anomaly_hist(self) -> History:
     obj: DBObject = DBObject(0, "tab")
     hist: History = History([
         # 0
         HistoryElem(
             Operation(Operation.Type.SET_ISOLATION,
                       isolation_level="serializable"), Result(), 0, 0, 0.0,
             0.0),
         # 1
         HistoryElem(
             Operation(Operation.Type.BEGIN,
                       isolation_level="serializable"), Result(), 0, 0, 0.0,
             0.0),
         # 2
         HistoryElem(Operation(Operation.Type.WRITE, obj=obj, value=0),
                     Result(), 0, 0, 0.0, 0.0),
         # 3
         HistoryElem(
             Operation(Operation.Type.COMMIT,
                       isolation_level="serializable"), Result(), 0, 0, 0.0,
             0.0),
         # 4
         HistoryElem(
             Operation(Operation.Type.SET_ISOLATION,
                       isolation_level="serializable"), Result(), 0, 1, 0.0,
             0.0),
         # 5
         HistoryElem(
             Operation(Operation.Type.BEGIN,
                       isolation_level="serializable"), Result(), 0, 1, 0.0,
             0.0),
         # 6
         HistoryElem(Operation(Operation.Type.WRITE, obj=obj, value=1),
                     Result(), 0, 1, 0.0, 0.0),
         # 7
         HistoryElem(Operation(Operation.Type.WRITE, obj=obj, value=2),
                     Result(), 0, 1, 0.0, 0.0),
         # 8
         HistoryElem(
             Operation(Operation.Type.COMMIT,
                       isolation_level="serializable"), Result(), 0, 1, 0.0,
             0.0),
         # 9
         HistoryElem(
             Operation(Operation.Type.SET_ISOLATION,
                       isolation_level="serializable"), Result(), 0, 2, 0.0,
             0.0),
         # 10
         HistoryElem(
             Operation(Operation.Type.BEGIN,
                       isolation_level="serializable"), Result(), 0, 2, 0.0,
             0.0),
         # 11
         HistoryElem(Operation(Operation.Type.READ, obj=obj),
                     Result(value=[("0,1", )]), 0, 2, 0.0, 0.0),
         # 12
         HistoryElem(
             Operation(Operation.Type.COMMIT,
                       isolation_level="serializable"), Result(), 0, 2, 0.0,
             0.0),
         # 13
         HistoryElem(
             Operation(Operation.Type.SET_ISOLATION,
                       isolation_level="serializable"), Result(), 0, 3, 0.0,
             0.0),
         # 14
         HistoryElem(
             Operation(Operation.Type.BEGIN,
                       isolation_level="serializable"), Result(), 0, 3, 0.0,
             0.0),
         # 15
         HistoryElem(Operation(Operation.Type.READ, obj=obj),
                     Result(value=[("0", )]), 0, 3, 0.0, 0.0),
         # 16
         HistoryElem(
             Operation(Operation.Type.COMMIT,
                       isolation_level="serializable"), Result(), 0, 8, 0.0,
             0.0),
     ])
     hist[2].op.stmt([])
     hist[6].op.stmt([0])
     hist[7].op.stmt([0, 1])
     return hist
예제 #8
0
    def get_history(self) -> History:
        obj_list = [
            DBObject(0, "tab"),
            DBObject(1, "tab"),
            DBObject(2, "tab"),
        ]
        self._obj_list = obj_list
        hist: History = History(
            [
                # 0
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 0,
                    0.0, 0.0),
                # 1
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 0,
                    0.0, 0.0),
                # 2
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[0], value=0),
                    Result(), 0, 0, 0.0, 0.0),
                # 3
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[1], value=0),
                    Result(), 0, 0, 0.0, 0.0),
                # 4
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[2], value=0),
                    Result(), 0, 0, 0.0, 0.0),
                # 5
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"), Result(), 0, 0,
                    0.0, 0.0),
                # 6
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 1,
                    0.0, 0.0),
                # 7
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 1,
                    0.0, 0.0),
                # 8
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[0], value=1),
                    Result(), 0, 1, 0.0, 0.0),
                # 9
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[1], value=3),
                    Result(), 0, 1, 0.0, 0.0),
                # 9
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"), Result(), 0, 1,
                    0.0, 0.0),
                # 11
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 2,
                    0.0, 0.0),
                # 12
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 2,
                    0.0, 0.0),
                # 13
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[1], value=1),
                    Result(), 0, 2, 0.0, 0.0),
                # 14
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[1], value=2),
                    Result(), 0, 2, 0.0, 0.0),
                # 15
                HistoryElem(Operation(Operation.Type.READ, obj=obj_list[0]),
                            Result(value=[("0,1", )]), 0, 2, 0.0, 0.0),
                # 16
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"), Result(), 0, 2,
                    0.0, 0.0),
                # 17
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 3,
                    0.0, 0.0),
                # 18
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 3,
                    0.0, 0.0),
                # 19
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[2], value=1),
                    Result(), 0, 3, 0.0, 0.0),
                # 20
                HistoryElem(
                    Operation(Operation.Type.ROLLBACK,
                              isolation_level="serializable"), Result(), 0, 3,
                    0.0, 0.0),
                # 21
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 4,
                    0.0, 0.0),
                # 22
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 4,
                    0.0, 0.0),
                # 23
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[2], value=2),
                    Result(), 0, 4, 0.0, 0.0),
                # 24
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"),
                    Result(exception=TimeoutError("Connection Reset")),
                    0,
                    4,
                    0.0,
                    0.0,
                ),
                # 25
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 5,
                    0.0, 0.0),
                # 26
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 5,
                    0.0, 0.0),
                # 27
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[2], value=3),
                    Result(), 0, 5, 0.0, 0.0),
                # 28
                HistoryElem(
                    Operation(Operation.Type.ROLLBACK,
                              isolation_level="serializable"),
                    Result(exception=TimeoutError("Connection Reset")),
                    0,
                    5,
                    0.0,
                    0.0,
                ),
                # 29
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 6,
                    0.0, 0.0),
                # 30
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 6,
                    0.0, 0.0),
                # 31
                HistoryElem(
                    Operation(Operation.Type.WRITE, obj=obj_list[2], value=4),
                    Result(exception=TimeoutError("Connection Reset")),
                    0,
                    6,
                    0.0,
                    0.0,
                ),
                # 32
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 7,
                    0.0, 0.0),
                # 33
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 7,
                    0.0, 0.0),
                # 34
                HistoryElem(
                    Operation(Operation.Type.READ, obj=obj_list[2]),
                    Result(exception=TimeoutError("Connection Reset")),
                    0,
                    7,
                    0.0,
                    0.0,
                ),
                # 35
                HistoryElem(
                    Operation(Operation.Type.SET_ISOLATION,
                              isolation_level="serializable"), Result(), 0, 8,
                    0.0, 0.0),
                # 36
                HistoryElem(
                    Operation(Operation.Type.BEGIN,
                              isolation_level="serializable"), Result(), 0, 8,
                    0.0, 0.0),
                # 37
                HistoryElem(Operation(Operation.Type.READ, obj=obj_list[0]),
                            Result(value=[("0,1", )]), 0, 8, 0.0, 0.0),
                # 38
                HistoryElem(Operation(Operation.Type.READ, obj=obj_list[1]),
                            Result(value=[("0,1,2", )]), 0, 8, 0.0, 0.0),
                # 39
                HistoryElem(Operation(Operation.Type.READ, obj=obj_list[2]),
                            Result(value=[("0", )]), 0, 8, 0.0, 0.0),
                # 40
                HistoryElem(
                    Operation(Operation.Type.COMMIT,
                              isolation_level="serializable"), Result(), 0, 8,
                    0.0, 0.0),
            ])

        hist[2].op.stmt([])
        hist[3].op.stmt([])
        hist[4].op.stmt([])
        hist[8].op.stmt([0])
        hist[9].op.stmt([0])
        hist[13].op.stmt([0])
        hist[14].op.stmt([0, 1])

        return hist