Example #1
0
    def test_lock_missing(_global_cache, _global_get, _global_watch,
                          _global_compare_and_swap, uuid):
        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        lock_value = _cache._LOCKED_FOR_WRITE + b".adifferentlock"
        _global_get.return_value = _future_result(lock_value)
        _global_watch.return_value = _future_result(None)
        _global_compare_and_swap.return_value = _future_result(True)

        with warnings.catch_warnings(record=True) as logged:
            assert _cache.global_unlock_for_write(b"key",
                                                  lock).result() is None
            logged = [
                warning for warning in logged
                if warning.category is RuntimeWarning
            ]
            assert len(logged) == 1

        _global_get.assert_called_once_with(b"key")
        _global_watch.assert_not_called()
        _global_compare_and_swap.assert_not_called()
Example #2
0
    def test_not_last_time_fail_once(_global_cache, _global_get, _global_watch,
                                     _global_compare_and_swap, uuid):
        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        new_lock_value = _cache._LOCKED_FOR_WRITE + b".whatevs"
        old_lock_value = new_lock_value + lock
        _global_get.return_value = _future_result(old_lock_value)
        _global_watch.return_value = _future_result(None)
        _global_compare_and_swap.side_effect = (
            _future_result(False),
            _future_result(True),
        )

        assert _cache.global_unlock_for_write(b"key", lock).result() is None
        _global_get.assert_has_calls([
            mock.call(b"key"),
            mock.call(b"key"),
        ])
        _global_watch.assert_has_calls([
            mock.call(b"key", old_lock_value),
            mock.call(b"key", old_lock_value),
        ])
        _global_compare_and_swap.assert_has_calls([
            mock.call(b"key", new_lock_value, expires=64),
            mock.call(b"key", new_lock_value, expires=64),
        ])
Example #3
0
    def test_lock_overwritten(_global_cache, _global_get, _global_watch,
                              _global_compare_and_swap, uuid):
        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        lock_value = b"SOMERANDOMVALUE"
        _global_get.return_value = _future_result(lock_value)
        _global_watch.return_value = _future_result(None)
        _global_compare_and_swap.return_value = _future_result(True)

        with warnings.catch_warnings(record=True) as logged:
            assert _cache.global_unlock_for_write(b"key",
                                                  lock).result() is None
            logged = [
                warning for warning in logged
                if warning.category is RuntimeWarning
            ]
            assert len(logged) == 1

        _global_get.assert_called_once_with(b"key")
        _global_watch.assert_called_once_with(b"key", lock_value)
        _global_compare_and_swap.assert_called_once_with(b"key",
                                                         b"",
                                                         expires=64)
Example #4
0
def put(entity, options):
    """Store an entity in datastore.

    The entity can be a new entity to be saved for the first time or an
    existing entity that has been updated.

    Args:
        entity_pb (datastore.Entity): The entity to be stored.
        options (_options.Options): Options for this request.

    Returns:
        tasklets.Future: Result will be completed datastore key
            (datastore.Key) for the entity.
    """
    context = context_module.get_context()
    use_global_cache = context._use_global_cache(entity.key, options)
    use_datastore = context._use_datastore(entity.key, options)
    if not (use_global_cache or use_datastore):
        raise TypeError("use_global_cache and use_datastore can't both be False")

    if not use_datastore and entity.key.is_partial:
        raise TypeError("Can't store partial keys when use_datastore is False")

    lock = None
    entity_pb = helpers.entity_to_protobuf(entity)
    cache_key = _cache.global_cache_key(entity.key)
    if use_global_cache and not entity.key.is_partial:
        if use_datastore:
            lock = yield _cache.global_lock_for_write(cache_key)
        else:
            expires = context._global_cache_timeout(entity.key, options)
            cache_value = entity_pb.SerializeToString()
            yield _cache.global_set(cache_key, cache_value, expires=expires)

    if use_datastore:
        transaction = context.transaction
        if transaction:
            batch = _get_commit_batch(transaction, options)
        else:
            batch = _batch.get_batch(_NonTransactionalCommitBatch, options)

        key_pb = yield batch.put(entity_pb)
        if key_pb:
            key = helpers.key_from_protobuf(key_pb)
        else:
            key = None

        if lock:
            if transaction:

                def callback():
                    _cache.global_unlock_for_write(cache_key, lock).result()

                context.call_on_transaction_complete(callback)

            else:
                yield _cache.global_unlock_for_write(cache_key, lock)

        raise tasklets.Return(key)
Example #5
0
    def lock_unlock_key():  # pragma: NO COVER
        lock = yield _cache.global_lock_for_write(key)
        cache_value = yield _cache.global_get(key)
        assert lock in cache_value

        yield _cache.global_unlock_for_write(key, lock)
        cache_value = yield _cache.global_get(key)
        assert lock not in cache_value
Example #6
0
def delete(key, options):
    """Delete an entity from Datastore.

    Deleting an entity that doesn't exist does not result in an error. The
    result is the same regardless.

    Args:
        key (datastore.Key): The key for the entity to be deleted.
        options (_options.Options): Options for this request.

    Returns:
        tasklets.Future: Will be finished when entity is deleted. Result will
            always be :data:`None`.
    """
    context = context_module.get_context()
    use_global_cache = context._use_global_cache(key, options)
    use_datastore = context._use_datastore(key, options)
    transaction = context.transaction

    if use_global_cache:
        cache_key = _cache.global_cache_key(key)

    if use_datastore:
        if use_global_cache:
            lock = yield _cache.global_lock_for_write(cache_key)

        if transaction:
            batch = _get_commit_batch(transaction, options)
        else:
            batch = _batch.get_batch(_NonTransactionalCommitBatch, options)

        yield batch.delete(key)

    if use_global_cache:
        if transaction:

            def callback():
                _cache.global_unlock_for_write(cache_key, lock).result()

            context.call_on_transaction_complete(callback)

        elif use_datastore:
            yield _cache.global_unlock_for_write(cache_key, lock)

        else:
            yield _cache.global_delete(cache_key)
Example #7
0
    def test_transient_error(_global_cache, _global_get, _global_watch, uuid):
        class TransientError(Exception):
            pass

        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(TransientError,),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        lock_value = _cache._LOCKED_FOR_WRITE + lock
        _global_get.return_value = _future_result(lock_value)
        _global_watch.return_value = _future_exception(TransientError())

        assert _cache.global_unlock_for_write(b"key", lock).result() is None
        _global_get.assert_called_once_with(b"key")
        _global_watch.assert_called_once_with(b"key", lock_value)
Example #8
0
    def test_last_time(
        _global_cache, _global_get, _global_watch, _global_compare_and_swap, uuid
    ):
        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        lock_value = _cache._LOCKED_FOR_WRITE + lock
        _global_get.return_value = _future_result(lock_value)
        _global_watch.return_value = _future_result(None)
        _global_compare_and_swap.return_value = _future_result(True)

        assert _cache.global_unlock_for_write(b"key", lock).result() is None
        _global_get.assert_called_once_with(b"key")
        _global_watch.assert_called_once_with(b"key", lock_value)
        _global_compare_and_swap.assert_called_once_with(b"key", b"", expires=32)
Example #9
0
    def test_no_value_in_cache(_global_cache, _global_get,
                               global_set_if_not_exists, uuid):
        lock = b".arandomuuid"

        _global_cache.return_value = mock.Mock(
            transient_errors=(),
            strict_write=False,
            spec=("transient_errors", "strict_write"),
        )

        _global_get.return_value = _future_result(None)
        global_set_if_not_exists.return_value = _future_result(True)

        with warnings.catch_warnings(record=True) as logged:
            assert _cache.global_unlock_for_write(b"key",
                                                  lock).result() is None
            logged = [
                warning for warning in logged
                if warning.category is RuntimeWarning
            ]
            assert len(logged) == 1

        _global_get.assert_called_once_with(b"key")
        global_set_if_not_exists.assert_not_called()
Example #10
0
 def callback():
     _cache.global_unlock_for_write(cache_key, lock).result()