Example #1
0
    async def begin(self, read_only: bool = False) -> ITransaction:
        """Starts a new transaction.
        """
        # already has txn registered, as long as connection is closed, it
        # is safe
        txn: typing.Optional[ITransaction] = task_vars.txn.get()
        if (txn is not None and txn.manager == self and txn.status
                in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT)):
            # re-use txn if possible
            txn.status = Status.ACTIVE
            if (txn._db_conn is not None
                    and getattr(txn._db_conn, '_in_use', None) is None):
                try:
                    await self._close_txn(txn)
                except Exception:
                    logger.warn('Unable to close spurious connection',
                                exc_info=True)
        else:
            txn = Transaction(self, read_only=read_only)

        try:
            txn.user = get_authenticated_user_id()
        except RequestNotFound:
            pass

        await txn.tpc_begin()

        # make sure to explicitly set!
        task_vars.txn.set(txn)

        return txn
Example #2
0
async def _test_pg_txn(postgres, guillotina_main):
    """Test a low level transaction"""
    dsn = "postgres://postgres:@localhost:5432/guillotina"
    partition_object = "guillotina.db.interfaces.IPartition"
    aps = APgStorage(dsn=dsn, partition=partition_object, name='db')
    await aps.initialize()
    conn = await aps.open()
    obj = Root()
    writer = IWriter(obj)
    tm = TransactionManager(DummyStorage())
    txn = Transaction(tm)
    await aps.tpc_begin(txn, conn)
    await aps.precommit(txn)
    await aps.store(ROOT_ID, 0, writer, obj, txn)
    await aps.tpc_vote(txn)
    await aps.tpc_finish(txn)
    await aps.close(conn)

    tm = TransactionManager(DummyStorage())
    txn = Transaction(tm)
    await aps.tpc_begin(txn, conn)
    result = await aps.load(txn, ROOT_ID)
    await aps.abort(txn)
    await aps.close(txn._db_conn)
    obj2 = reader(result)
    assert obj.__name__ == obj2.__name__
    await cleanup(aps)
Example #3
0
async def test_do_not_cache_large_object(guillotina_main, loop):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = BasicCache(txn)
    txn._cache = cache
    ob = create_content()
    ob.foobar = "X" * cache.max_cache_record_size  # push size above cache threshold
    storage.store(None, None, None, ob, txn)
    loaded = await txn.get(ob.__uuid__)
    assert id(loaded) != id(ob)
    assert loaded.__uuid__ == ob.__uuid__
Example #4
0
async def test_do_not_cache_large_object(dummy_guillotina):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = MemoryCache(storage, txn)
    txn._cache = cache
    ob = create_content()
    ob.foobar = 'X' * cache.max_cache_record_size  # push size above cache threshold
    storage.store(ob)
    loaded = await txn.get(ob._p_oid)
    assert id(loaded) != id(ob)
    assert loaded._p_oid == ob._p_oid
    assert len(cache._actions) == 0
Example #5
0
    async def test_record_transaction_cache_hit_container(
            self, dummy_guillotina, metrics_registry):
        storage = AsyncMock()
        mng = TransactionManager(storage)
        cache = AsyncMock()

        cache.get.return_value = {
            "state": pickle.dumps(create_content(Container)),
            "zoid": ROOT_ID,
            "tid": 1,
            "id": "foobar",
        }
        strategy = AsyncMock()
        txn = Transaction(mng, cache=cache, strategy=strategy)

        await txn.get("foobar")

        assert (metrics_registry.get_sample_value("guillotina_cache_ops_total",
                                                  {
                                                      "type": "_get",
                                                      "result": "hit"
                                                  }) is None)

        assert (metrics_registry.get_sample_value("guillotina_cache_ops_total",
                                                  {
                                                      "type": "_get",
                                                      "result": "hit_roots"
                                                  }) == 1.0)
Example #6
0
async def test_fill_cache_doesnt_cache_large_objects(guillotina_main,
                                                     mocked_cache_set):
    tm = mocks.MockTransactionManager()
    txn = Transaction(tm)
    cache = BasicCache(txn)

    # Mock storing an object that is over the limit
    obj = Mock()
    obj.__uuid__ = "foo"
    obj.__serial__ = "bar"
    obj.__name__ = "ba"
    obj.__of__ = "bi"

    pickled = MagicMock()
    pickled.__len__.return_value = BasicCache.max_cache_record_size + 10

    await cache.store_object(obj, pickled)

    # Call fill_cache and check that caching was skipped
    await cache.fill_cache()

    cache.set.assert_not_called()

    # Now add smaller object and check that is cached
    pickled.__len__.return_value = 1
    await cache.store_object(obj, pickled)
    await cache.fill_cache()
    cache.set.assert_called_once()
Example #7
0
async def test_cache_object(dummy_guillotina):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = MemoryCache(storage, txn)
    txn._cache = cache
    ob = create_content()
    storage.store(ob)
    loaded = await txn.get(ob._p_oid)
    assert id(loaded) != id(ob)
    assert loaded._p_oid == ob._p_oid
    assert cache._actions[0]['action'] == 'stored'

    # and load from cache
    await txn.get(ob._p_oid)
    assert cache._actions[-1]['action'] == 'loaded'
Example #8
0
    async def begin(self, request=None):
        """Starts a new transaction.
        """

        self._db_conn = await self._storage.open()

        if request is None:
            if self.request is None:
                self.request = get_current_request()
            request = self.request

        user = get_authenticated_user_id(request)
        if self._txn is not None:
            if self._pool is None:
                self._pool = LifoQueue()
            # Save the actual transaction and start a new one
            self._pool.put(self._txn)

        self._txn = txn = Transaction(self, request=request)

        # CACHE!!

        if user is not None:
            txn.user = user
        await txn.tpc_begin(self._db_conn)

        return txn
Example #9
0
async def test_cache_object(guillotina_main, loop):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = BasicCache(txn)
    txn._cache = cache
    ob = create_content()
    storage.store(None, None, None, ob, txn)
    loaded = await txn.get(ob.__uuid__)
    assert id(loaded) != id(ob)
    assert loaded.__uuid__ == ob.__uuid__
    assert cache._hits == 0
    assert cache._misses == 1

    # and load from cache
    await txn.get(ob.__uuid__)
    assert cache._hits == 1
Example #10
0
    async def begin(self, request=None):
        """Starts a new transaction.
        """

        if request is None:
            try:
                request = get_current_request()
            except RequestNotFound:
                pass

        user = None

        txn = None

        # already has txn registered, as long as connection is closed, it
        # is safe
        if (getattr(request, '_txn', None) is not None and request._txn.status
                in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT)):
            # re-use txn if possible
            txn = request._txn
            txn.status = Status.ACTIVE
            if txn._db_conn is not None:
                try:
                    await self._close_txn(txn)
                except Exception:
                    logger.warn('Unable to close spurious connection',
                                exc_info=True)
        else:
            txn = Transaction(self, request=request)

        self._last_txn = txn

        if request is not None:
            # register tm and txn with request
            request._tm = self
            request._txn = txn
            user = get_authenticated_user_id(request)

        if user is not None:
            txn.user = user

        db_conn = self._last_db_conn = await self._storage.open()
        txn._query_count_start = _get_conn_query_count(db_conn)
        await txn.tpc_begin(db_conn)

        return txn
    async def begin(self, request=None):
        """Starts a new transaction.
        """

        if request is None:
            try:
                request = get_current_request()
            except RequestNotFound:
                pass

        user = None

        txn = None

        # already has txn registered, as long as connection is closed, it
        # is safe
        if (getattr(request, '_txn', None) is not None and
                request._txn.status in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT)):
            # re-use txn if possible
            txn = request._txn
            txn.status = Status.ACTIVE
            if (txn._db_conn is not None and
                    getattr(txn._db_conn, '_in_use', None) is None):
                try:
                    await self._close_txn(txn)
                except Exception:
                    logger.warn('Unable to close spurious connection', exc_info=True)
        else:
            txn = Transaction(self, request=request)

        self._last_txn = txn

        if request is not None:
            # register tm and txn with request
            request._tm = self
            request._txn = txn
            user = get_authenticated_user_id(request)

        if user is not None:
            txn.user = user

        await txn.tpc_begin()

        return txn
    async def begin(self, request=None):
        """Starts a new transaction.
        """

        db_conn = self._last_db_conn = await self._storage.open()

        if request is None:
            try:
                request = get_current_request()
            except RequestNotFound:
                pass

        user = None

        txn = None
        # already has txn registered, as long as connection is closed, it
        # is safe
        if (getattr(request, '_txn', None) is not None
                and request._txn._db_conn is None
                and request._txn.status in (Status.ABORTED, Status.COMMITTED)):
            # re-use txn if possible
            txn = request._txn
            txn.status = Status.ACTIVE
        # XXX do we want to auto clean up here? Or throw an error?
        # This will break tests that are starting multiple transactions
        # else:
        #     await self._close_txn(request._txn)
        else:
            txn = Transaction(self, request=request)

        self._last_txn = txn

        if request is not None:
            # register tm and txn with request
            request._tm = self
            request._txn = txn
            user = get_authenticated_user_id(request)

        if user is not None:
            txn.user = user

        await txn.tpc_begin(db_conn)

        return txn
Example #13
0
async def test_cache_object_from_child(guillotina_main, loop):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = BasicCache(txn)
    txn._cache = cache
    ob = create_content()
    parent = create_content()
    ob.__parent__ = parent
    storage.store(None, None, None, parent, txn)
    storage.store(None, None, None, ob, txn)

    loaded = await txn.get_child(parent, ob.id)
    assert cache._hits == 0
    loaded = await txn.get_child(parent, ob.id)
    assert cache._hits == 1

    assert id(loaded) != id(ob)
    assert loaded.__uuid__ == ob.__uuid__
Example #14
0
async def test_cache_object_from_child(dummy_guillotina):
    tm = mocks.MockTransactionManager()
    storage = tm._storage
    txn = Transaction(tm)
    cache = MemoryCache(storage, txn)
    txn._cache = cache
    ob = create_content()
    parent = create_content()
    ob.__parent__ = parent
    storage.store(parent)
    storage.store(ob)

    loaded = await txn.get_child(parent, ob.id)
    assert len(cache._actions) == 1
    assert cache._actions[0]['action'] == 'stored'
    loaded = await txn.get_child(parent, ob.id)
    assert cache._actions[-1]['action'] == 'loaded'

    assert id(loaded) != id(ob)
    assert loaded._p_oid == ob._p_oid
Example #15
0
async def _test_read_something(postgres, guillotina_main):
    """Low level test checks that root is there"""
    dsn = "postgres://postgres:@localhost:5432/guillotina"
    partition_object = "guillotina.db.interfaces.IPartition"
    aps = APgStorage(dsn=dsn, partition=partition_object, name='db')
    await aps.initialize()
    conn = await aps.open()
    tm = TransactionManager(aps)
    txn = Transaction(tm)
    await txn.tpc_begin(conn)
    lasttid = await aps.last_transaction(txn)
    await aps.load(txn, ROOT_ID)
    await aps.abort(txn)
    await aps.remove()
    await aps.close(txn._db_conn)
    await cleanup(aps)
    assert lasttid == 1
Example #16
0
    async def test_record_transaction_cache_empty(self, dummy_guillotina,
                                                  metrics_registry):
        storage = AsyncMock()
        mng = TransactionManager(storage)
        cache = AsyncMock()

        cache.get.return_value = transaction._EMPTY
        strategy = AsyncMock()
        txn = Transaction(mng, cache=cache, strategy=strategy)

        ob = create_content(Container)
        with pytest.raises(KeyError):
            await txn.get_annotation(ob, "foobar")

        assert (metrics_registry.get_sample_value(
            "guillotina_cache_ops_total", {
                "type": "_get_annotation",
                "result": "hit_empty"
            }) == 1.0)
Example #17
0
async def test_no_tid_created_for_reads(dummy_request, loop):
    tm = mocks.MockTransactionManager()
    trns = Transaction(tm, loop=loop, read_only=True)
    await trns.tpc_begin()
    assert trns._tid is None
Example #18
0
async def test_tid_created_for_writes(dummy_request, loop):
    tm = mocks.MockTransactionManager()
    trns = Transaction(tm, loop=loop)
    await trns.tpc_begin()
    assert trns._tid == 1
Example #19
0
async def test_no_tid_created_for_reads(dummy_request, loop):
    dummy_request._db_write_enabled = False
    tm = mocks.MockTransactionManager()
    trns = Transaction(tm, dummy_request, loop=loop)
    await trns.tpc_begin()
    assert trns._tid is None